Skip to content

Commit

Permalink
refactor: rename category ui
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <i@innei.in>
  • Loading branch information
Innei committed Aug 20, 2024
1 parent 918d85a commit 5f30bfa
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 35 deletions.
13 changes: 11 additions & 2 deletions src/renderer/src/hooks/biz/useNavigateEntry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ import {
getStableRouterNavigate,
} from "@renderer/atoms/route"
import { setSidebarActiveView } from "@renderer/atoms/sidebar"
import { ROUTE_ENTRY_PENDING, ROUTE_FEED_PENDING } from "@renderer/constants"
import {
ROUTE_ENTRY_PENDING,
ROUTE_FEED_IN_FOLDER,
ROUTE_FEED_PENDING,
} from "@renderer/constants"
import { FeedViewType } from "@renderer/lib/enum"
import { isUndefined } from "lodash-es"

type NavigateEntryOptions = Partial<{
feedId: string | null
entryId: string | null
view: FeedViewType
folderName: string
}>
/**
* @description a hook to navigate to `feedId`, `entryId`, add search for `view`, `level`
Expand All @@ -19,14 +24,18 @@ type NavigateEntryOptions = Partial<{
export const useNavigateEntry = () => navigateEntry

export const navigateEntry = (options: NavigateEntryOptions) => {
const { entryId, feedId, view } = options || {}
const { entryId, feedId, view, folderName } = options || {}
const { params, searchParams } = getReadonlyRoute()
let finalFeedId = feedId || params.feedId || ROUTE_FEED_PENDING

if ("feedId" in options && feedId === null) {
finalFeedId = ROUTE_FEED_PENDING
}

if (folderName) {
finalFeedId = `${ROUTE_FEED_IN_FOLDER}${folderName}`
}

finalFeedId = encodeURIComponent(finalFeedId)
const nextSearchParams = new URLSearchParams(searchParams)

Expand Down
10 changes: 9 additions & 1 deletion src/renderer/src/hooks/biz/useRouteParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
import {
FEED_COLLECTION_LIST,
ROUTE_ENTRY_PENDING,
ROUTE_FEED_IN_FOLDER,
ROUTE_FEED_PENDING,
} from "@renderer/constants"
import { FeedViewType } from "@renderer/lib/enum"
Expand Down Expand Up @@ -45,9 +46,13 @@ export interface BizRouteParams {
isAllFeeds: boolean
isPendingEntry: boolean

folderName?: string
}

const parseRouteParams = (params: Params<any>, search: URLSearchParams): BizRouteParams => {
const parseRouteParams = (
params: Params<any>,
search: URLSearchParams,
): BizRouteParams => {
const _view = search.get("view")

const view =
Expand All @@ -63,6 +68,9 @@ const parseRouteParams = (params: Params<any>, search: URLSearchParams): BizRout
isCollection: params.feedId === FEED_COLLECTION_LIST,
isAllFeeds: params.feedId === ROUTE_FEED_PENDING,
isPendingEntry: params.entryId === ROUTE_ENTRY_PENDING,
folderName: params.feedId?.startsWith(ROUTE_FEED_IN_FOLDER) ?
params.feedId.slice(ROUTE_FEED_IN_FOLDER.length) :
undefined,
}
}

Expand Down
122 changes: 90 additions & 32 deletions src/renderer/src/modules/feed-column/category.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { MotionButtonBase } from "@renderer/components/ui/button"
import { LoadingCircle } from "@renderer/components/ui/loading"
import { ROUTE_FEED_IN_FOLDER, views } from "@renderer/constants"
import { useNavigateEntry } from "@renderer/hooks/biz/useNavigateEntry"
Expand All @@ -16,11 +17,10 @@ import {
import { useFeedUnreadStore } from "@renderer/store/unread"
import { useMutation } from "@tanstack/react-query"
import { AnimatePresence, m } from "framer-motion"
import { memo, useEffect, useRef, useState } from "react"
import { Fragment, memo, useEffect, useRef, useState } from "react"

import { useModalStack } from "../../components/ui/modal/stacked/hooks"
import { CategoryRemoveDialogContent } from "./category-remove-dialog"
import { CategoryRenameContent } from "./category-rename-dialog"
import { FeedItem } from "./item"
import { UnreadNumber } from "./unread-number"

Expand Down Expand Up @@ -83,7 +83,7 @@ function FeedCategoryImpl({
navigate({
entryId: null,
// TODO joint feedId is too long, need to be optimized
feedId: `${ROUTE_FEED_IN_FOLDER}${folderName}`,
folderName,
view,
})
}
Expand Down Expand Up @@ -113,6 +113,31 @@ function FeedCategoryImpl({
},
})

const [isCategoryEditing, setIsCategoryEditing] = useState(false)

const renameMutation = useMutation({
mutationFn: async ({
lastCategory,
newCategory,
}: {
lastCategory: string
newCategory: string
}) => subscriptionActions.renameCategory(lastCategory, newCategory),
onMutate({ lastCategory, newCategory }) {
const routeParams = getRouteParams()

if (routeParams.folderName === lastCategory) {
navigate({
folderName: newCategory,
})
}

setIsCategoryEditing(false)
},
})

const isCategoryIsWaiting = renameMutation.isPending || isChangePending

return (
<div tabIndex={-1} onClick={stopPropagation}>
{!!showCollapse && (
Expand All @@ -123,7 +148,9 @@ function FeedCategoryImpl({
)}
onClick={(e) => {
e.stopPropagation()
setCategoryActive()
if (!isCategoryEditing) {
setCategoryActive()
}
}}
onContextMenu={(e) => {
showNativeMenu(
Expand All @@ -150,18 +177,7 @@ function FeedCategoryImpl({
type: "text",
label: "Rename category",
click: () => {
present({
title: "Rename Category",
clickOutsideToDismiss: true,
content: ({ dismiss }) => (
<CategoryRenameContent
feedIdList={ids}
category={folderName || ""}
view={view}
onSuccess={dismiss}
/>
),
})
setIsCategoryEditing(true)
},
},
{
Expand All @@ -186,6 +202,7 @@ function FeedCategoryImpl({
<button
type="button"
onClick={(e) => {
if (isCategoryEditing) return
e.stopPropagation()
setOpen(!open)
}}
Expand All @@ -195,25 +212,66 @@ function FeedCategoryImpl({
)}
tabIndex={-1}
>
{isChangePending ? (
{isCategoryIsWaiting ? (
<LoadingCircle size="small" className="mr-2 size-[16px]" />
) : (
<div className="mr-2 size-[16px]">
<i className="i-mgc-right-cute-fi transition-transform" />
</div>
)}
) : isCategoryEditing ?
(
<MotionButtonBase
onClick={() => {
setIsCategoryEditing(false)
}}
className="center flex"
>
<i className="i-mgc-close-cute-re text-red-500" />
</MotionButtonBase>
) :
(
<div className="mr-2 size-[16px]">
<i className="i-mgc-right-cute-fi transition-transform" />
</div>
)}
</button>
<span
className={cn(
"truncate",
!showUnreadCount &&
(unread ? "font-bold" : "font-medium opacity-70"),
)}
>
{folderName}
</span>
{isCategoryEditing ? (
<form
className="ml-3 flex w-full items-center"
onSubmit={(e) => {
e.preventDefault()

return renameMutation.mutateAsync({
lastCategory: folderName!,
newCategory: e.currentTarget.category.value,
})
}}
>
<input
name="category"
autoFocus
defaultValue={folderName}
className="w-full appearance-none bg-transparent caret-accent"
/>
<MotionButtonBase
type="submit"
className="center -mr-1 flex size-5 shrink-0 rounded-lg text-green-600 hover:bg-theme-button-hover dark:text-green-400"
>
<i className="i-mgc-check-filled size-3" />
</MotionButtonBase>
</form>
) : (
<Fragment>
<span
className={cn(
"grow truncate",
!showUnreadCount &&
(unread ? "font-bold" : "font-medium opacity-70"),
)}
>
{folderName}
</span>

<UnreadNumber unread={unread} className="ml-2" />
</Fragment>
)}
</div>
<UnreadNumber unread={unread} className="ml-2" />
</div>
)}
<AnimatePresence>
Expand Down
8 changes: 8 additions & 0 deletions src/renderer/src/services/subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ class SubscriptionServiceStatic extends BaseService<SubscriptionModelWithId> {
return this.table.where("userId").equals(userId).delete()
}
}

async renameCategory(userId: string, feedIdList: string[], category: string) {
return this.table
.where("userId")
.equals(userId)
.and((item) => feedIdList.includes(item.feedId))
.modify({ category })
}
}

export const SubscriptionService = new SubscriptionServiceStatic()
44 changes: 44 additions & 0 deletions src/renderer/src/store/subscription/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,50 @@ class SubscriptionActions {
),
)
}

async renameCategory(lastCategory: string, newCategory: string) {
const subscriptionIds = [] as string[]
const state = get()
for (const feedId in state.data) {
const subscription = state.data[feedId]
if (
subscription.category === lastCategory ||
subscription.defaultCategory === lastCategory
) {
subscriptionIds.push(feedId)
}
}

set((state) =>
produce(state, (state) => {
for (const feedId of subscriptionIds) {
const subscription = state.data[feedId]
if (subscription) {
subscription.category = newCategory
subscription.defaultCategory = undefined
}
}
}),
)

return doMutationAndTransaction(
() =>
apiClient.categories.$patch({
json: {
feedIdList: subscriptionIds,
category: newCategory,
},
}),
async () =>
// Db

SubscriptionService.renameCategory(
whoami()!.id,
subscriptionIds,
newCategory,
),
)
}
}

export const subscriptionActions = new SubscriptionActions()
Expand Down

0 comments on commit 5f30bfa

Please sign in to comment.