From 66cf3dd82851e9c206513047c7ea40329a5fb712 Mon Sep 17 00:00:00 2001 From: an-lee Date: Thu, 11 Jan 2024 17:36:23 +0800 Subject: [PATCH] refactor webApi --- enjoy/src/api/client.ts | 15 ++++---- enjoy/src/renderer/components/login-form.tsx | 10 +++--- .../src/renderer/components/lookup-result.tsx | 4 +-- enjoy/src/renderer/components/posts/posts.tsx | 10 ++---- .../components/stories/stories-segment.tsx | 4 +-- .../components/users/users-rankings.tsx | 10 ++---- .../context/app-settings-provider.tsx | 35 ++++++++++++++----- enjoy/src/renderer/pages/stories.tsx | 4 +-- enjoy/src/renderer/pages/story-preview.tsx | 4 +-- enjoy/src/renderer/pages/story.tsx | 14 ++++---- enjoy/src/renderer/pages/vocabulary.tsx | 4 +-- 11 files changed, 62 insertions(+), 52 deletions(-) diff --git a/enjoy/src/api/client.ts b/enjoy/src/api/client.ts index bf130586..1d76fd8c 100644 --- a/enjoy/src/api/client.ts +++ b/enjoy/src/api/client.ts @@ -6,9 +6,11 @@ const ONE_MINUTE = 1000 * 60; // 1 minute export class Client { public api: AxiosInstance; + public baseUrl: string; constructor(options: { baseUrl: string; accessToken?: string }) { const { baseUrl, accessToken } = options; + this.baseUrl = baseUrl; this.api = axios.create({ baseURL: baseUrl, @@ -20,7 +22,7 @@ export class Client { this.api.interceptors.request.use((config) => { config.headers.Authorization = `Bearer ${accessToken}`; - console.info( + console.debug( config.method.toUpperCase(), config.baseURL + config.url, config.data, @@ -30,7 +32,7 @@ export class Client { }); this.api.interceptors.response.use( (response) => { - console.info( + console.debug( response.status, response.config.method.toUpperCase(), response.config.baseURL + response.config.url @@ -63,7 +65,7 @@ export class Client { return this.api.post("/api/sessions", decamelizeKeys(params)); } - me() { + me(): Promise { return this.api.get("/api/me"); } @@ -151,7 +153,7 @@ export class Client { sourceId?: string; sourceType?: string; }[] - ): Promise<{ successCount: number; total: number }> { + ): Promise<{ successCount: number; errors: string[], total: number }> { return this.api.post("/api/lookups/batch", { lookups: decamelizeKeys(lookups, { deep: true }), }); @@ -171,6 +173,7 @@ export class Client { ): Promise< { meanings: MeaningType[]; + pendingLookups?: LookupType[]; } & PagyResponseType > { return this.api.get(`/api/stories/${storyId}/meanings`, { @@ -220,11 +223,11 @@ export class Client { }); } - starStory(storyId: string) { + starStory(storyId: string): Promise<{ starred: boolean }> { return this.api.post(`/api/mine/stories`, decamelizeKeys({ storyId })); } - unstarStory(storyId: string) { + unstarStory(storyId: string): Promise<{ starred: boolean }> { return this.api.delete(`/api/mine/stories/${storyId}`); } } diff --git a/enjoy/src/renderer/components/login-form.tsx b/enjoy/src/renderer/components/login-form.tsx index c71ec358..9fdb38b8 100644 --- a/enjoy/src/renderer/components/login-form.tsx +++ b/enjoy/src/renderer/components/login-form.tsx @@ -5,10 +5,10 @@ import { t } from "i18next"; export const LoginForm = () => { const { toast } = useToast(); - const { EnjoyApp, login, apiUrl } = useContext(AppSettingsProviderContext); + const { EnjoyApp, login, webApi } = useContext(AppSettingsProviderContext); const handleMixinLogin = () => { - const url = `${apiUrl}/sessions/new?provider=mixin`; + const url = `${webApi.baseUrl}/sessions/new?provider=mixin`; EnjoyApp.view.load(url, { x: 0, y: 0 }); }; @@ -34,7 +34,7 @@ export const LoginForm = () => { const provider = new URL(url).pathname.split("/")[2]; const code = new URL(url).searchParams.get("code"); - if (!url.startsWith(apiUrl)) { + if (!url.startsWith(webApi.baseUrl)) { toast({ title: t("error"), description: t("invalidRedirectUrl"), @@ -44,7 +44,7 @@ export const LoginForm = () => { } if (provider && code) { - EnjoyApp.webApi + webApi .auth({ provider, code }) .then((user) => { login(user); @@ -70,7 +70,7 @@ export const LoginForm = () => { EnjoyApp.view.removeViewStateListeners(); EnjoyApp.view.remove(); }; - }, [apiUrl]); + }, [webApi]); return (
diff --git a/enjoy/src/renderer/components/lookup-result.tsx b/enjoy/src/renderer/components/lookup-result.tsx index 333757e9..bc2ab41b 100644 --- a/enjoy/src/renderer/components/lookup-result.tsx +++ b/enjoy/src/renderer/components/lookup-result.tsx @@ -18,7 +18,7 @@ export const LookupResult = (props: { const [loading, setLoading] = useState(true); if (!word) return null; - const { EnjoyApp } = useContext(AppSettingsProviderContext); + const { webApi } = useContext(AppSettingsProviderContext); const lookup = (retries = 0) => { if (!word) return; @@ -28,7 +28,7 @@ export const LookupResult = (props: { } retries += 1; - EnjoyApp.webApi + webApi .lookup({ word, context, diff --git a/enjoy/src/renderer/components/posts/posts.tsx b/enjoy/src/renderer/components/posts/posts.tsx index 30abad1b..87139641 100644 --- a/enjoy/src/renderer/components/posts/posts.tsx +++ b/enjoy/src/renderer/components/posts/posts.tsx @@ -1,19 +1,13 @@ import { useContext, useEffect, useState } from "react"; -import { Client } from "@/api"; import { AppSettingsProviderContext } from "@renderer/context"; import { t } from "i18next"; export const Posts = () => { - const { apiUrl, user } = useContext(AppSettingsProviderContext); + const { webApi } = useContext(AppSettingsProviderContext); const [posts, setPosts] = useState([]); - const client = new Client({ - baseUrl: apiUrl, - accessToken: user.accessToken, - }); - const fetchPosts = async () => { - client.posts().then( + webApi.posts().then( (res) => { setPosts(res.posts); }, diff --git a/enjoy/src/renderer/components/stories/stories-segment.tsx b/enjoy/src/renderer/components/stories/stories-segment.tsx index 365fc0b5..b5629cfa 100644 --- a/enjoy/src/renderer/components/stories/stories-segment.tsx +++ b/enjoy/src/renderer/components/stories/stories-segment.tsx @@ -7,10 +7,10 @@ import { AppSettingsProviderContext } from "@renderer/context"; export const StoriesSegment = () => { const [stories, setStorys] = useState([]); - const { EnjoyApp } = useContext(AppSettingsProviderContext); + const { webApi } = useContext(AppSettingsProviderContext); const fetchStorys = async () => { - EnjoyApp.webApi.mineStories().then((response) => { + webApi.mineStories().then((response) => { if (response?.stories) { setStorys(response.stories); } diff --git a/enjoy/src/renderer/components/users/users-rankings.tsx b/enjoy/src/renderer/components/users/users-rankings.tsx index 04cadb66..422cac6c 100644 --- a/enjoy/src/renderer/components/users/users-rankings.tsx +++ b/enjoy/src/renderer/components/users/users-rankings.tsx @@ -8,7 +8,6 @@ import { CardHeader, CardContent, } from "@renderer/components/ui"; -import { Client } from "@/api"; import { AppSettingsProviderContext } from "@renderer/context"; import { t } from "i18next"; import { formatDuration } from "@renderer/lib/utils"; @@ -28,16 +27,11 @@ const RankingsCard = (props: { range: "day" | "week" | "month" | "year" | "all"; }) => { const { range } = props; - const { apiUrl, user } = useContext(AppSettingsProviderContext); + const { webApi } = useContext(AppSettingsProviderContext); const [rankings, setRankings] = useState([]); - const client = new Client({ - baseUrl: apiUrl, - accessToken: user.accessToken, - }); - const fetchRankings = async () => { - client.rankings(range).then( + webApi.rankings(range).then( (res) => { setRankings(res.rankings); }, diff --git a/enjoy/src/renderer/context/app-settings-provider.tsx b/enjoy/src/renderer/context/app-settings-provider.tsx index 3cf18a58..c57521fb 100644 --- a/enjoy/src/renderer/context/app-settings-provider.tsx +++ b/enjoy/src/renderer/context/app-settings-provider.tsx @@ -1,8 +1,9 @@ import { createContext, useEffect, useState } from "react"; import { WEB_API_URL } from "@/constants"; +import { Client } from "@/api"; type AppSettingsProviderState = { - apiUrl: string; + webApi: Client; user: UserType | null; initialized: boolean; version?: string; @@ -19,7 +20,7 @@ type AppSettingsProviderState = { }; const initialState: AppSettingsProviderState = { - apiUrl: WEB_API_URL, + webApi: null, user: null, initialized: false, }; @@ -35,6 +36,7 @@ export const AppSettingsProvider = ({ const [initialized, setInitialized] = useState(false); const [version, setVersion] = useState(""); const [apiUrl, setApiUrl] = useState(WEB_API_URL); + const [webApi, setWebApi] = useState(null); const [user, setUser] = useState(null); const [libraryPath, setLibraryPath] = useState(""); const [whisperModelsPath, setWhisperModelsPath] = useState(""); @@ -48,7 +50,6 @@ export const AppSettingsProvider = ({ fetchLibraryPath(); fetchModel(); fetchFfmpegConfig(); - fetchApiUrl(); }, []); useEffect(() => { @@ -59,6 +60,17 @@ export const AppSettingsProvider = ({ validate(); }, [user, libraryPath, whisperModel, ffmpegConfig]); + useEffect(() => { + if (!apiUrl) return; + + setWebApi( + new Client({ + baseUrl: apiUrl, + accessToken: user?.accessToken, + }) + ); + }, [user, apiUrl]); + const fetchFfmpegConfig = async () => { const config = await EnjoyApp.settings.getFfmpegConfig(); setFfmegConfig(config); @@ -70,10 +82,18 @@ export const AppSettingsProvider = ({ }; const fetchUser = async () => { + const apiUrl = await EnjoyApp.app.apiUrl(); + setApiUrl(apiUrl); + const currentUser = await EnjoyApp.settings.getUser(); if (!currentUser) return; - EnjoyApp.webApi.me().then((user) => { + const client = new Client({ + baseUrl: apiUrl, + accessToken: currentUser.accessToken, + }); + + client.me().then((user) => { if (user?.id) { login(currentUser); } else { @@ -113,9 +133,8 @@ export const AppSettingsProvider = ({ }; const fetchApiUrl = async () => { - const apiUrl = await EnjoyApp.app.apiUrl(); - setApiUrl(apiUrl); - } + return apiUrl; + }; const setModelHandler = async (name: string) => { await EnjoyApp.settings.setWhisperModel(name); @@ -133,7 +152,7 @@ export const AppSettingsProvider = ({ value={{ EnjoyApp, version, - apiUrl, + webApi, user, login, logout, diff --git a/enjoy/src/renderer/pages/stories.tsx b/enjoy/src/renderer/pages/stories.tsx index e513aba9..3777d131 100644 --- a/enjoy/src/renderer/pages/stories.tsx +++ b/enjoy/src/renderer/pages/stories.tsx @@ -5,10 +5,10 @@ import { AppSettingsProviderContext } from "@renderer/context"; export default () => { const [stories, setStorys] = useState([]); const [loading, setLoading] = useState(true); - const { EnjoyApp } = useContext(AppSettingsProviderContext); + const { webApi } = useContext(AppSettingsProviderContext); const fetchStorys = async () => { - EnjoyApp.webApi + webApi .mineStories() .then((response) => { if (response?.stories) { diff --git a/enjoy/src/renderer/pages/story-preview.tsx b/enjoy/src/renderer/pages/story-preview.tsx index b1ddeb28..ccb871dd 100644 --- a/enjoy/src/renderer/pages/story-preview.tsx +++ b/enjoy/src/renderer/pages/story-preview.tsx @@ -26,7 +26,7 @@ export default () => { }); const [loading, setLoading] = useState(true); const [readable, setReadable] = useState(true); - const { EnjoyApp } = useContext(AppSettingsProviderContext); + const { EnjoyApp, webApi } = useContext(AppSettingsProviderContext); const { toast } = useToast(); const [meanings, setMeanings] = useState([]); const [marked, setMarked] = useState(false); @@ -52,7 +52,7 @@ export default () => { const createStory = async () => { if (!story) return; - EnjoyApp.webApi + webApi .createStory({ url: story.metadata?.url || story.url, ...story, diff --git a/enjoy/src/renderer/pages/story.tsx b/enjoy/src/renderer/pages/story.tsx index dc74b6ce..2e794c59 100644 --- a/enjoy/src/renderer/pages/story.tsx +++ b/enjoy/src/renderer/pages/story.tsx @@ -16,7 +16,7 @@ nlp.plugin(paragraphs); let timeout: NodeJS.Timeout = null; export default () => { const { id } = useParams<{ id: string }>(); - const { EnjoyApp } = useContext(AppSettingsProviderContext); + const { webApi } = useContext(AppSettingsProviderContext); const [loading, setLoading] = useState(true); const [story, setStory] = useState(); const [meanings, setMeanings] = useState([]); @@ -26,7 +26,7 @@ export default () => { const [doc, setDoc] = useState(null); const fetchStory = async () => { - EnjoyApp.webApi + webApi .story(id) .then((story) => { setStory(story); @@ -41,7 +41,7 @@ export default () => { const fetchMeanings = async () => { setScanning(true); - EnjoyApp.webApi + webApi .storyMeanings(id, { items: 500 }) .then((response) => { if (!response) return; @@ -88,14 +88,14 @@ export default () => { }); }); - EnjoyApp.webApi.lookupInBatch(vocabulary).then((response) => { + webApi.lookupInBatch(vocabulary).then((response) => { const { errors } = response; if (errors.length > 0) { console.warn(errors); return; } - EnjoyApp.webApi.extractVocabularyFromStory(id).then(() => { + webApi.extractVocabularyFromStory(id).then(() => { fetchStory(); if (pendingLookups.length > 0) return; @@ -108,11 +108,11 @@ export default () => { if (!story) return; if (story.starred) { - EnjoyApp.webApi.unstarStory(id).then((result) => { + webApi.unstarStory(id).then((result) => { setStory({ ...story, starred: result.starred }); }); } else { - EnjoyApp.webApi.starStory(id).then((result) => { + webApi.starStory(id).then((result) => { setStory({ ...story, starred: result.starred }); }); } diff --git a/enjoy/src/renderer/pages/vocabulary.tsx b/enjoy/src/renderer/pages/vocabulary.tsx index 8e05f480..73d5102a 100644 --- a/enjoy/src/renderer/pages/vocabulary.tsx +++ b/enjoy/src/renderer/pages/vocabulary.tsx @@ -11,14 +11,14 @@ export default () => { const [loading, setLoading] = useState(false); const [meanings, setMeanings] = useState([]); - const { EnjoyApp } = useContext(AppSettingsProviderContext); + const { webApi } = useContext(AppSettingsProviderContext); const [currentIndex, setCurrentIndex] = useState(0); const [nextPage, setNextPage] = useState(1); const fetchMeanings = async (page: number = nextPage) => { if (!page) return; - EnjoyApp.webApi + webApi .mineMeanings({ page, items: 10 }) .then((response) => { setMeanings([...meanings, ...response.meanings]);