diff --git a/public/locales/en.json b/public/locales/en.json index 967bcb40..a1b3125b 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -1603,7 +1603,9 @@ "tracking": { "action": { "button": { - "add_tracking": "Add tracking" + "add_tracking": "Add tracking", + "track_privately": "Track privately", + "track_publicly": "Track publicly" }, "login": { "label": { diff --git a/src/lib/graphql/fragments/TrackFragments.ts b/src/lib/graphql/fragments/TrackFragments.ts index 97e2261e..eef0ce1b 100644 --- a/src/lib/graphql/fragments/TrackFragments.ts +++ b/src/lib/graphql/fragments/TrackFragments.ts @@ -38,6 +38,7 @@ export const TRACKER_BIND_FIELDS = gql` icon + supportsPrivateTracking supportsTrackDeletion scores statuses { diff --git a/src/lib/graphql/fragments/TrackRecordFragments.ts b/src/lib/graphql/fragments/TrackRecordFragments.ts index fac62261..24148730 100644 --- a/src/lib/graphql/fragments/TrackRecordFragments.ts +++ b/src/lib/graphql/fragments/TrackRecordFragments.ts @@ -38,5 +38,6 @@ export const TRACK_RECORD_BIND_FIELDS = gql` displayScore startDate finishDate + private } `; diff --git a/src/lib/graphql/generated/graphql.ts b/src/lib/graphql/generated/graphql.ts index abca2529..2b1628e8 100644 --- a/src/lib/graphql/generated/graphql.ts +++ b/src/lib/graphql/generated/graphql.ts @@ -3012,11 +3012,11 @@ export type TrackerBaseFieldsFragment = { __typename?: 'TrackerType', id: number export type TrackerSettingFieldsFragment = { __typename?: 'TrackerType', authUrl?: string | null, id: number, name: string, icon: string, isLoggedIn: boolean, isTokenExpired: boolean }; -export type TrackerBindFieldsFragment = { __typename?: 'TrackerType', icon: string, supportsTrackDeletion: boolean, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } }; +export type TrackerBindFieldsFragment = { __typename?: 'TrackerType', icon: string, supportsPrivateTracking: boolean, supportsTrackDeletion: boolean, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, private: boolean }> } }; export type TrackRecordSearchFieldsFragment = { __typename?: 'TrackSearchType', id: number, remoteId: string, title: string, trackingUrl: string, coverUrl: string, publishingType: string, startDate: string, publishingStatus: string, summary: string, score: number, totalChapters: number }; -export type TrackRecordBindFieldsFragment = { __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }; +export type TrackRecordBindFieldsFragment = { __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, private: boolean }; export type UpdaterMangaFieldsFragment = { __typename?: 'MangaUpdateType', status: MangaJobStatus, manga: { __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null, unreadCount: number, downloadCount: number, bookmarkCount: number, hasDuplicateChapters: boolean, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, firstUnreadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, isRead: boolean, mangaId: number } | null, lastReadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, lastReadAt: string } | null, latestReadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, lastReadAt: string } | null, latestFetchedChapter?: { __typename?: 'ChapterType', id: number, fetchedAt: string } | null, latestUploadedChapter?: { __typename?: 'ChapterType', id: number, uploadDate: string } | null } }; @@ -3141,7 +3141,7 @@ export type UpdateChapterMutationVariables = Exact<{ }>; -export type UpdateChapterMutation = { __typename?: 'Mutation', updateChapter?: { __typename?: 'UpdateChapterPayload', chapter: { __typename?: 'ChapterType', id: number, isBookmarked?: boolean, isRead?: boolean, lastReadAt?: string, lastPageRead?: number, manga?: { __typename?: 'MangaType', id: number, unreadCount: number, bookmarkCount: number, lastReadChapter?: { __typename?: 'ChapterType', id: number } | null, latestReadChapter?: { __typename?: 'ChapterType', id: number } | null, firstUnreadChapter?: { __typename?: 'ChapterType', id: number } | null } } } | null, deleteDownloadedChapter?: { __typename?: 'DeleteDownloadedChapterPayload', chapters: { __typename?: 'ChapterType', id: number, isDownloaded: boolean, manga: { __typename?: 'MangaType', id: number, downloadCount: number } } } | null, trackProgress?: { __typename?: 'TrackProgressPayload', trackRecords: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } | null }; +export type UpdateChapterMutation = { __typename?: 'Mutation', updateChapter?: { __typename?: 'UpdateChapterPayload', chapter: { __typename?: 'ChapterType', id: number, isBookmarked?: boolean, isRead?: boolean, lastReadAt?: string, lastPageRead?: number, manga?: { __typename?: 'MangaType', id: number, unreadCount: number, bookmarkCount: number, lastReadChapter?: { __typename?: 'ChapterType', id: number } | null, latestReadChapter?: { __typename?: 'ChapterType', id: number } | null, firstUnreadChapter?: { __typename?: 'ChapterType', id: number } | null } } } | null, deleteDownloadedChapter?: { __typename?: 'DeleteDownloadedChapterPayload', chapters: { __typename?: 'ChapterType', id: number, isDownloaded: boolean, manga: { __typename?: 'MangaType', id: number, downloadCount: number } } } | null, trackProgress?: { __typename?: 'TrackProgressPayload', trackRecords: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, private: boolean }> } | null }; export type UpdateChaptersMutationVariables = Exact<{ input: UpdateChaptersInput; @@ -3155,7 +3155,7 @@ export type UpdateChaptersMutationVariables = Exact<{ }>; -export type UpdateChaptersMutation = { __typename?: 'Mutation', updateChapters?: { __typename?: 'UpdateChaptersPayload', chapters: Array<{ __typename?: 'ChapterType', id: number, isBookmarked?: boolean, isRead?: boolean, lastReadAt?: string, lastPageRead?: number, manga?: { __typename?: 'MangaType', id: number, unreadCount: number, bookmarkCount: number, lastReadChapter?: { __typename?: 'ChapterType', id: number } | null, latestReadChapter?: { __typename?: 'ChapterType', id: number } | null, firstUnreadChapter?: { __typename?: 'ChapterType', id: number } | null } }> } | null, deleteDownloadedChapters?: { __typename?: 'DeleteDownloadedChaptersPayload', chapters: Array<{ __typename?: 'ChapterType', id: number, isDownloaded: boolean, manga: { __typename?: 'MangaType', id: number, downloadCount: number } }> } | null, trackProgress?: { __typename?: 'TrackProgressPayload', trackRecords: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } | null }; +export type UpdateChaptersMutation = { __typename?: 'Mutation', updateChapters?: { __typename?: 'UpdateChaptersPayload', chapters: Array<{ __typename?: 'ChapterType', id: number, isBookmarked?: boolean, isRead?: boolean, lastReadAt?: string, lastPageRead?: number, manga?: { __typename?: 'MangaType', id: number, unreadCount: number, bookmarkCount: number, lastReadChapter?: { __typename?: 'ChapterType', id: number } | null, latestReadChapter?: { __typename?: 'ChapterType', id: number } | null, firstUnreadChapter?: { __typename?: 'ChapterType', id: number } | null } }> } | null, deleteDownloadedChapters?: { __typename?: 'DeleteDownloadedChaptersPayload', chapters: Array<{ __typename?: 'ChapterType', id: number, isDownloaded: boolean, manga: { __typename?: 'MangaType', id: number, downloadCount: number } }> } | null, trackProgress?: { __typename?: 'TrackProgressPayload', trackRecords: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, private: boolean }> } | null }; export type ClearDownloaderMutationVariables = Exact<{ input?: InputMaybe; @@ -3415,13 +3415,11 @@ export type TrackerLogoutMutationVariables = Exact<{ export type TrackerLogoutMutation = { __typename?: 'Mutation', logoutTracker: { __typename?: 'LogoutTrackerPayload', tracker: { __typename?: 'TrackerType', authUrl?: string | null, id: number, name: string, icon: string, isLoggedIn: boolean, isTokenExpired: boolean } } }; export type TrackerBindMutationVariables = Exact<{ - mangaId: Scalars['Int']['input']; - remoteId: Scalars['LongString']['input']; - trackerId: Scalars['Int']['input']; + input: BindTrackInput; }>; -export type TrackerBindMutation = { __typename?: 'Mutation', bindTrack: { __typename?: 'BindTrackPayload', trackRecord: { __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, manga: { __typename?: 'MangaType', id: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, trackerId: number }> } } } } }; +export type TrackerBindMutation = { __typename?: 'Mutation', bindTrack: { __typename?: 'BindTrackPayload', trackRecord: { __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, private: boolean, manga: { __typename?: 'MangaType', id: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, trackerId: number }> } } } } }; export type TrackerUnbindMutationVariables = Exact<{ input: UnbindTrackInput; @@ -3435,14 +3433,14 @@ export type TrackerUpdateBindMutationVariables = Exact<{ }>; -export type TrackerUpdateBindMutation = { __typename?: 'Mutation', updateTrack: { __typename?: 'UpdateTrackPayload', trackRecord?: { __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, manga: { __typename?: 'MangaType', id: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, trackerId: number }> } } } | null } }; +export type TrackerUpdateBindMutation = { __typename?: 'Mutation', updateTrack: { __typename?: 'UpdateTrackPayload', trackRecord?: { __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, private: boolean, manga: { __typename?: 'MangaType', id: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, trackerId: number }> } } } | null } }; export type TrackerFetchBindMutationVariables = Exact<{ recordId: Scalars['Int']['input']; }>; -export type TrackerFetchBindMutation = { __typename?: 'Mutation', fetchTrack: { __typename?: 'FetchTrackPayload', trackRecord: { __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string } } }; +export type TrackerFetchBindMutation = { __typename?: 'Mutation', fetchTrack: { __typename?: 'FetchTrackPayload', trackRecord: { __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, private: boolean } } }; export type UpdateLibraryMutationVariables = Exact<{ input?: InputMaybe; @@ -3653,7 +3651,7 @@ export type GetMangaTrackRecordsQueryVariables = Exact<{ }>; -export type GetMangaTrackRecordsQuery = { __typename?: 'Query', manga: { __typename?: 'MangaType', id: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } } }; +export type GetMangaTrackRecordsQuery = { __typename?: 'Query', manga: { __typename?: 'MangaType', id: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, private: boolean }> } } }; export type GetMangaCategoriesQueryVariables = Exact<{ id: Scalars['Int']['input']; @@ -3670,7 +3668,7 @@ export type GetMangaToMigrateQueryVariables = Exact<{ }>; -export type GetMangaToMigrateQuery = { __typename?: 'Query', manga: { __typename?: 'MangaType', id: number, inLibrary: boolean, title: string, chapters?: { __typename?: 'ChapterNodeList', totalCount: number, nodes: Array<{ __typename?: 'ChapterType', id: number, chapterNumber: number, isRead: boolean, isDownloaded: boolean, isBookmarked: boolean, manga: { __typename?: 'MangaType', id: number } }> }, categories?: { __typename?: 'CategoryNodeList', nodes: Array<{ __typename?: 'CategoryType', id: number }> }, trackRecords?: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number }> } } }; +export type GetMangaToMigrateQuery = { __typename?: 'Query', manga: { __typename?: 'MangaType', id: number, inLibrary: boolean, title: string, chapters?: { __typename?: 'ChapterNodeList', totalCount: number, nodes: Array<{ __typename?: 'ChapterType', id: number, chapterNumber: number, isRead: boolean, isDownloaded: boolean, isBookmarked: boolean, manga: { __typename?: 'MangaType', id: number } }> }, categories?: { __typename?: 'CategoryNodeList', nodes: Array<{ __typename?: 'CategoryType', id: number }> }, trackRecords?: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, private: boolean }> } } }; export type GetMangasBaseQueryVariables = Exact<{ after?: InputMaybe; @@ -3790,7 +3788,7 @@ export type GetTrackersSettingsQuery = { __typename?: 'Query', trackers: { __typ export type GetTrackersBindQueryVariables = Exact<{ [key: string]: never; }>; -export type GetTrackersBindQuery = { __typename?: 'Query', trackers: { __typename?: 'TrackerNodeList', totalCount: number, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null }, nodes: Array<{ __typename?: 'TrackerType', icon: string, supportsTrackDeletion: boolean, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } }> } }; +export type GetTrackersBindQuery = { __typename?: 'Query', trackers: { __typename?: 'TrackerNodeList', totalCount: number, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null }, nodes: Array<{ __typename?: 'TrackerType', icon: string, supportsPrivateTracking: boolean, supportsTrackDeletion: boolean, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, private: boolean }> } }> } }; export type TrackerSearchQueryVariables = Exact<{ query: Scalars['String']['input']; diff --git a/src/lib/graphql/mutations/TrackerMutation.ts b/src/lib/graphql/mutations/TrackerMutation.ts index b8c67ef7..a1592dd4 100644 --- a/src/lib/graphql/mutations/TrackerMutation.ts +++ b/src/lib/graphql/mutations/TrackerMutation.ts @@ -50,8 +50,8 @@ export const TRACKER_LOGOUT = gql` export const TRACKER_BIND = gql` ${TRACK_RECORD_BIND_FIELDS} - mutation TRACKER_BIND($mangaId: Int!, $remoteId: LongString!, $trackerId: Int!) { - bindTrack(input: { mangaId: $mangaId, remoteId: $remoteId, trackerId: $trackerId }) { + mutation TRACKER_BIND($input: BindTrackInput!) { + bindTrack(input: $input) { trackRecord { ...TRACK_RECORD_BIND_FIELDS manga { diff --git a/src/lib/graphql/queries/MangaQuery.ts b/src/lib/graphql/queries/MangaQuery.ts index 0de01e99..2e44b197 100644 --- a/src/lib/graphql/queries/MangaQuery.ts +++ b/src/lib/graphql/queries/MangaQuery.ts @@ -108,6 +108,7 @@ export const GET_MANGA_TO_MIGRATE = gql` id remoteId trackerId + private } } } diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index ff888ae7..3db93a7e 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -3184,9 +3184,15 @@ export class RequestManager { mangaId: number, trackerId: number, remoteId: string, + asPrivate: boolean, options?: MutationOptions, ): AbortableApolloMutationResponse { - return this.doRequest(GQLMethod.MUTATION, TRACKER_BIND, { mangaId, remoteId, trackerId }, options); + return this.doRequest( + GQLMethod.MUTATION, + TRACKER_BIND, + { input: { mangaId, remoteId, trackerId, private: asPrivate } }, + options, + ); } public unbindTracker( diff --git a/src/modules/manga/services/Mangas.ts b/src/modules/manga/services/Mangas.ts index 9ad647df..aeae9921 100644 --- a/src/modules/manga/services/Mangas.ts +++ b/src/modules/manga/services/Mangas.ts @@ -381,8 +381,12 @@ export class Mangas { copy: () => trackBindingsToAdd.map( (trackRecord) => - requestManager.bindTracker(mangaToMigrateTo.id, trackRecord.trackerId, trackRecord.remoteId) - .response, + requestManager.bindTracker( + mangaToMigrateTo.id, + trackRecord.trackerId, + trackRecord.remoteId, + trackRecord.private, + ).response, ), cleanup: () => mode === 'migrate' diff --git a/src/modules/tracker/Tracker.types.ts b/src/modules/tracker/Tracker.types.ts index 02467095..03c9d398 100644 --- a/src/modules/tracker/Tracker.types.ts +++ b/src/modules/tracker/Tracker.types.ts @@ -56,12 +56,14 @@ export type TTrackRecordBind = TTrackRecordBase & | 'displayScore' | 'startDate' | 'finishDate' + | 'private' >; export type TTrackerManga = TrackRecordSearchFieldsFragment; export type TTrackerBase = Pick; export type TTrackerSearch = TTrackerBase & Pick; -export type TTrackerBind = TTrackerBase & Pick; +export type TTrackerBind = TTrackerBase & + Pick; export type TrackerIdInfo = Pick; export type LoggedInInfo = Pick; export type TrackRecordTrackerInfo = Pick; diff --git a/src/modules/tracker/components/TrackerSearch.tsx b/src/modules/tracker/components/TrackerSearch.tsx index 1eacf5ea..6d13d0de 100644 --- a/src/modules/tracker/components/TrackerSearch.tsx +++ b/src/modules/tracker/components/TrackerSearch.tsx @@ -21,6 +21,7 @@ import InfoIcon from '@mui/icons-material/Info'; import PopupState, { bindPopover, bindTrigger } from 'material-ui-popup-state'; import Popover from '@mui/material/Popover'; import Typography from '@mui/material/Typography'; +import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { EmptyViewAbsoluteCentered } from '@/modules/core/components/feedback/EmptyViewAbsoluteCentered.tsx'; import { LoadingPlaceholder } from '@/modules/core/components/feedback/LoadingPlaceholder.tsx'; @@ -35,28 +36,34 @@ import { MangaType } from '@/lib/graphql/generated/graphql.ts'; import { MangaIdInfo } from '@/modules/manga/Manga.types.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts'; -import { Tracker, TrackerIdInfo, TTrackerBase } from '@/modules/tracker/Tracker.types.ts'; +import { Tracker, TrackerIdInfo, TTrackerBind } from '@/modules/tracker/Tracker.types.ts'; +import { CustomButtonIcon } from '@/modules/core/components/buttons/CustomButtonIcon.tsx'; +import { CustomTooltip } from '@/modules/core/components/CustomTooltip.tsx'; const TrackButton = ({ mangaId, selectedTrackerRemoteId, trackerId, closeSearchMode, + supportsPrivateTracking, }: { trackerId: TrackerIdInfo['id']; mangaId: MangaIdInfo['id']; selectedTrackerRemoteId: string | undefined; closeSearchMode: () => void; + supportsPrivateTracking: boolean; }) => { const { t } = useTranslation(); const [bindTracker, bindTrackerMutation] = requestManager.useBindTracker(); - const trackManga = () => { + const trackManga = (asPrivate: boolean) => { if (selectedTrackerRemoteId === undefined) { return; } - bindTracker({ variables: { mangaId, remoteId: selectedTrackerRemoteId, trackerId } }) + bindTracker({ + variables: { input: { mangaId, remoteId: selectedTrackerRemoteId, trackerId, private: asPrivate } }, + }) .then(() => { makeToast(t('manga.action.track.add.label.success'), 'success'); closeSearchMode(); @@ -74,17 +81,34 @@ const TrackButton = ({ right: 0, bottom: 0, paddingBottom: DIALOG_PADDING, + gap: 2, + px: DIALOG_PADDING, }} > + {supportsPrivateTracking && ( + + trackManga(true)} + > + + + + )} ); }; @@ -96,7 +120,7 @@ export const TrackerSearch = ({ trackedId, }: { manga: MangaIdInfo & Pick; - tracker: Pick; + tracker: TTrackerBind; closeSearchMode: () => void; trackedId?: string; }) => { @@ -221,6 +245,7 @@ export const TrackerSearch = ({ trackerId={tracker.id} closeSearchMode={closeSearchMode} selectedTrackerRemoteId={selectedTrackerRemoteId} + supportsPrivateTracking={tracker.supportsPrivateTracking} /> )} diff --git a/src/modules/tracker/components/cards/TrackerActiveCard.tsx b/src/modules/tracker/components/cards/TrackerActiveCard.tsx index c37b98d1..175ade0e 100644 --- a/src/modules/tracker/components/cards/TrackerActiveCard.tsx +++ b/src/modules/tracker/components/cards/TrackerActiveCard.tsx @@ -27,6 +27,8 @@ import Typography from '@mui/material/Typography'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import PopupState, { bindDialog, bindMenu, bindTrigger } from 'material-ui-popup-state'; import { useMemo, useState } from 'react'; +import Badge from '@mui/material/Badge'; +import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; import { CustomTooltip } from '@/modules/core/components/CustomTooltip.tsx'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { Trackers } from '@/modules/tracker/services/Trackers.ts'; @@ -50,7 +52,6 @@ const TrackerActiveLink = ({ children, url }: { children: React.ReactNode; url: ); type TTrackerActive = Pick; -type TTrackRecordActive = Pick; const TrackerActiveRemoveBind = ({ trackerRecordId, tracker, @@ -139,6 +140,33 @@ const TrackerActiveRemoveBind = ({ ); }; +const TrackerUpdatePrivateStatus = ({ + trackRecordId, + isPrivate, + closeMenu, +}: { + trackRecordId: TrackRecordType['id']; + isPrivate: boolean; + closeMenu: () => void; +}) => { + const { t } = useTranslation(); + + return ( + { + requestManager + .updateTrackerBind(trackRecordId, { private: !isPrivate }) + .response.catch((e) => + makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)), + ); + closeMenu(); + }} + > + {t(isPrivate ? 'tracking.action.button.track_publicly' : 'tracking.action.button.track_privately')} + + ); +}; +type TTrackRecordActive = Pick; const TrackerActiveHeader = ({ trackRecord, tracker, @@ -158,14 +186,24 @@ const TrackerActiveHeader = ({ paddingBottom: 2, }} > - - - + + + + ) : null + } + > + + + + @@ -202,6 +240,11 @@ const TrackerActiveHeader = ({ onClick={() => setHideMenu(true)} onClose={onClose} />, + , ]}