chore(frontend): update shortcut store

This commit is contained in:
Steven 2023-11-10 10:11:02 +08:00
parent b3e766926d
commit f3f2218e91
6 changed files with 36 additions and 31 deletions

View File

@ -235,7 +235,7 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
<Input className="w-full" type="text" placeholder="github slash" value={tag} onChange={handleTagsInputChange} /> <Input className="w-full" type="text" placeholder="github slash" value={tag} onChange={handleTagsInputChange} />
{tagSuggestions.length > 0 && ( {tagSuggestions.length > 0 && (
<div className="w-full flex flex-row justify-start items-start mt-2"> <div className="w-full flex flex-row justify-start items-start mt-2">
<Icon.Asterisk className="w-4 h-auto shrink-0 mx-1 text-gray-400 dark:text-gray-600" /> <Icon.Asterisk className="w-4 h-auto shrink-0 mx-1 text-gray-400 dark:text-gray-500" />
<div className="w-auto flex flex-row justify-start items-start flex-wrap gap-x-2 gap-y-1"> <div className="w-auto flex flex-row justify-start items-start flex-wrap gap-x-2 gap-y-1">
{tagSuggestions.map((tag) => ( {tagSuggestions.map((tag) => (
<span <span
@ -312,7 +312,10 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
)} )}
onClick={() => setShowOpenGraphMetadata(!showOpenGraphMetadata)} onClick={() => setShowOpenGraphMetadata(!showOpenGraphMetadata)}
> >
<span className="text-sm flex flex-row justify-start items-center">Social media metadata</span> <span className="text-sm flex flex-row justify-start items-center">
Social media metadata
<Icon.Sparkles className="w-4 h-auto shrink-0 ml-1 text-blue-600 dark:text-blue-500" />
</span>
<button className="w-7 h-7 p-1 rounded-md"> <button className="w-7 h-7 p-1 rounded-md">
<Icon.ChevronDown className={classnames("w-4 h-auto text-gray-500", showOpenGraphMetadata ? "transform rotate-180" : "")} /> <Icon.ChevronDown className={classnames("w-4 h-auto text-gray-500", showOpenGraphMetadata ? "transform rotate-180" : "")} />
</button> </button>

View File

@ -25,7 +25,7 @@ const Header: React.FC = () => {
return ( return (
<> <>
<div className="w-full bg-gray-50 dark:bg-zinc-900 border-b border-b-gray-200 dark:border-b-zinc-800"> <div className="w-full bg-gray-50 dark:bg-zinc-800 border-b border-b-gray-200 dark:border-b-zinc-800">
<div className="w-full max-w-8xl mx-auto px-3 md:px-12 py-5 flex flex-row justify-between items-center"> <div className="w-full max-w-8xl mx-auto px-3 md:px-12 py-5 flex flex-row justify-between items-center">
<div className="flex flex-row justify-start items-center shrink mr-2"> <div className="flex flex-row justify-start items-center shrink mr-2">
<Link to="/" className="text-lg cursor-pointer flex flex-row justify-start items-center dark:text-gray-400"> <Link to="/" className="text-lg cursor-pointer flex flex-row justify-start items-center dark:text-gray-400">

View File

@ -103,27 +103,21 @@ const ShortcutView = (props: Props) => {
{shortcut.tags.length === 0 && <span className="text-gray-400 text-sm leading-4 italic">No tags</span>} {shortcut.tags.length === 0 && <span className="text-gray-400 text-sm leading-4 italic">No tags</span>}
</div> </div>
<div className="w-full flex mt-2 gap-2 overflow-x-auto"> <div className="w-full flex mt-2 gap-2 overflow-x-auto">
<Tooltip title="Creator" variant="solid" placement="top" arrow>
<div className="w-auto px-2 leading-6 flex flex-row justify-start items-center flex-nowra whitespace-nowrap border rounded-full text-gray-500 text-sm dark:border-zinc-800">
<Icon.User className="w-4 h-auto mr-1" />
<span className="max-w-[4rem] sm:max-w-[6rem] truncate">{shortcut.creator.nickname}</span>
</div>
</Tooltip>
<Tooltip title={t(`shortcut.visibility.${shortcut.visibility.toLowerCase()}.description`)} variant="solid" placement="top" arrow> <Tooltip title={t(`shortcut.visibility.${shortcut.visibility.toLowerCase()}.description`)} variant="solid" placement="top" arrow>
<div <div
className="w-auto px-2 leading-6 flex flex-row justify-start items-center flex-nowrap whitespace-nowrap border rounded-full cursor-pointer text-gray-500 text-sm dark:border-zinc-800" className="w-auto px-2 leading-6 flex flex-row justify-start items-center flex-nowrap whitespace-nowrap border rounded-full cursor-pointer text-gray-500 dark:text-gray-400 text-sm dark:border-zinc-700"
onClick={() => viewStore.setFilter({ visibility: shortcut.visibility })} onClick={() => viewStore.setFilter({ visibility: shortcut.visibility })}
> >
<VisibilityIcon className="w-4 h-auto mr-1" visibility={shortcut.visibility} /> <VisibilityIcon className="w-4 h-auto mr-1 opacity-60" visibility={shortcut.visibility} />
{t(`shortcut.visibility.${shortcut.visibility.toLowerCase()}.self`)} {t(`shortcut.visibility.${shortcut.visibility.toLowerCase()}.self`)}
</div> </div>
</Tooltip> </Tooltip>
<Tooltip title="View count" variant="solid" placement="top" arrow> <Tooltip title="View count" variant="solid" placement="top" arrow>
<Link <Link
to={`/shortcut/${shortcut.id}#analytics`} to={`/shortcut/${shortcut.id}#analytics`}
className="w-auto px-2 leading-6 flex flex-row justify-start items-center flex-nowrap whitespace-nowrap border rounded-full cursor-pointer text-gray-500 text-sm dark:border-zinc-800" className="w-auto px-2 leading-6 flex flex-row justify-start items-center flex-nowrap whitespace-nowrap border rounded-full cursor-pointer text-gray-500 dark:text-gray-400 text-sm dark:border-zinc-700"
> >
<Icon.BarChart2 className="w-4 h-auto mr-1" /> <Icon.BarChart2 className="w-4 h-auto mr-1 opacity-80" />
{t("shortcut.visits", { count: shortcut.view })} {t("shortcut.visits", { count: shortcut.view })}
</Link> </Link>
</Tooltip> </Tooltip>

View File

@ -1,4 +1,5 @@
import { createChannel, createClientFactory, FetchTransport } from "nice-grpc-web"; import { createChannel, createClientFactory, FetchTransport } from "nice-grpc-web";
import { ShortcutServiceDefinition } from "./types/proto/api/v2/shortcut_service";
import { SubscriptionServiceDefinition } from "./types/proto/api/v2/subscription_service"; import { SubscriptionServiceDefinition } from "./types/proto/api/v2/subscription_service";
import { UserServiceDefinition } from "./types/proto/api/v2/user_service"; import { UserServiceDefinition } from "./types/proto/api/v2/user_service";
import { UserSettingServiceDefinition } from "./types/proto/api/v2/user_setting_service"; import { UserSettingServiceDefinition } from "./types/proto/api/v2/user_setting_service";
@ -22,3 +23,5 @@ export const workspaceServiceClient = clientFactory.create(WorkspaceServiceDefin
export const userServiceClient = clientFactory.create(UserServiceDefinition, channel); export const userServiceClient = clientFactory.create(UserServiceDefinition, channel);
export const userSettingServiceClient = clientFactory.create(UserSettingServiceDefinition, channel); export const userSettingServiceClient = clientFactory.create(UserSettingServiceDefinition, channel);
export const shortcutServiceClient = clientFactory.create(ShortcutServiceDefinition, channel);

View File

@ -15,13 +15,6 @@ const shortcutService = {
return store.getState().shortcut; return store.getState().shortcut;
}, },
fetchWorkspaceShortcuts: async () => {
const data = (await api.getShortcutList({})).data;
const shortcuts = data.map((s) => convertResponseModelShortcut(s));
store.dispatch(setShortcuts(shortcuts));
return shortcuts;
},
getMyAllShortcuts: async () => { getMyAllShortcuts: async () => {
const data = (await api.getShortcutList()).data; const data = (await api.getShortcutList()).data;
const shortcuts = data.map((s) => convertResponseModelShortcut(s)); const shortcuts = data.map((s) => convertResponseModelShortcut(s));

View File

@ -1,30 +1,39 @@
import { create } from "zustand"; import { create } from "zustand";
import * as api from "../../helpers/api"; import { shortcutServiceClient } from "@/grpcweb";
import { Shortcut } from "@/types/proto/api/v2/shortcut_service";
const convertResponseModelShortcut = (shortcut: Shortcut): Shortcut => {
return {
...shortcut,
createdTs: shortcut.createdTs * 1000,
updatedTs: shortcut.updatedTs * 1000,
};
};
interface ShortcutState { interface ShortcutState {
shortcutMapById: Record<ShortcutId, Shortcut>; shortcutMapById: Record<ShortcutId, Shortcut>;
fetchShortcutList: () => Promise<Shortcut[]>;
getOrFetchShortcutById: (id: ShortcutId) => Promise<Shortcut>; getOrFetchShortcutById: (id: ShortcutId) => Promise<Shortcut>;
getShortcutById: (id: ShortcutId) => Shortcut; getShortcutById: (id: ShortcutId) => Shortcut;
getShortcutList: () => Shortcut[];
} }
const useShortcutStore = create<ShortcutState>()((set, get) => ({ const useShortcutStore = create<ShortcutState>()((set, get) => ({
shortcutMapById: {}, shortcutMapById: {},
fetchShortcutList: async () => {
const { shortcuts } = await shortcutServiceClient.listShortcuts({});
const shortcutMap = get().shortcutMapById;
shortcuts.forEach((shortcut) => {
shortcutMap[shortcut.id] = shortcut;
});
set(shortcutMap);
return shortcuts;
},
getOrFetchShortcutById: async (id: ShortcutId) => { getOrFetchShortcutById: async (id: ShortcutId) => {
const shortcutMap = get().shortcutMapById; const shortcutMap = get().shortcutMapById;
if (shortcutMap[id]) { if (shortcutMap[id]) {
return shortcutMap[id] as Shortcut; return shortcutMap[id] as Shortcut;
} }
const { data } = await api.getShortcutById(id); const { shortcut } = await shortcutServiceClient.getShortcut({
const shortcut = convertResponseModelShortcut(data); id: id,
});
if (!shortcut) {
throw new Error(`Shortcut with id ${id} not found`);
}
shortcutMap[id] = shortcut; shortcutMap[id] = shortcut;
set(shortcutMap); set(shortcutMap);
return shortcut; return shortcut;
@ -33,6 +42,9 @@ const useShortcutStore = create<ShortcutState>()((set, get) => ({
const shortcutMap = get().shortcutMapById; const shortcutMap = get().shortcutMapById;
return shortcutMap[id] as Shortcut; return shortcutMap[id] as Shortcut;
}, },
getShortcutList: () => {
return Object.values(get().shortcutMapById);
},
})); }));
export default useShortcutStore; export default useShortcutStore;