diff --git a/front/packages/models/src/account-internal.ts b/front/packages/models/src/account-internal.ts
index 28c80260..609d690d 100644
--- a/front/packages/models/src/account-internal.ts
+++ b/front/packages/models/src/account-internal.ts
@@ -17,71 +17,3 @@
* You should have received a copy of the GNU General Public License
* along with Kyoo. If not, see .
*/
-
-import { Platform } from "react-native";
-import { type ZodTypeAny, z } from "zod";
-import { type Account, AccountP } from "./accounts";
-
-const readAccounts = () => {
- const acc = storage.getString("accounts");
- if (!acc) return [];
- return z.array(AccountP).parse(JSON.parse(acc));
-};
-
-const writeAccounts = (accounts: Account[]) => {
- storage.set("accounts", JSON.stringify(accounts));
- if (Platform.OS === "web") {
- const selected = accounts.find((x) => x.selected);
- if (!selected) return;
- setCookie("account", selected);
- // cookie used for images and videos since we can't add Authorization headers in img or video tags.
- setCookie("X-Bearer", selected?.token.access_token);
- }
-};
-
-export const getCurrentAccount = () => {
- const accounts = readAccounts();
- return accounts.find((x) => x.selected);
-};
-
-export const addAccount = (account: Account) => {
- const accounts = readAccounts();
-
- // Prevent the user from adding the same account twice.
- if (accounts.find((x) => x.id === account.id)) {
- updateAccount(account.id, account);
- return;
- }
-
- for (const acc of accounts) acc.selected = false;
- accounts.push(account);
- writeAccounts(accounts);
-};
-
-export const removeAccounts = (filter: (acc: Account) => boolean) => {
- let accounts = readAccounts();
- accounts = accounts.filter((x) => !filter(x));
- if (!accounts.find((x) => x.selected) && accounts.length > 0) {
- accounts[0].selected = true;
- }
- writeAccounts(accounts);
-};
-
-export const updateAccount = (id: string, account: Account) => {
- const accounts = readAccounts();
- const idx = accounts.findIndex((x) => x.id === id);
- if (idx === -1) return;
-
- const selected = account.selected;
- if (selected) {
- for (const acc of accounts) acc.selected = false;
- // if account was already on the accounts list, we keep it selected.
- account.selected = selected;
- } else if (accounts[idx].selected) {
- // we just unselected the current account, focus another one.
- if (accounts.length > 0) accounts[0].selected = true;
- }
-
- accounts[idx] = account;
- writeAccounts(accounts);
-};
diff --git a/front/src/providers/account-provider.tsx b/front/src/providers/account-provider.tsx
index 7cb51142..44f033d4 100644
--- a/front/src/providers/account-provider.tsx
+++ b/front/src/providers/account-provider.tsx
@@ -1,8 +1,11 @@
import { type ReactNode, createContext, useEffect, useMemo } from "react";
import { Platform } from "react-native";
-import { type Account, type Token, type User, UserP } from "~/models";
+import { z } from "zod";
+import { type Account, AccountP, type Token, type User, UserP } from "~/models";
import { useFetch } from "~/query";
+import { removeAccounts, updateAccount } from "./account-store";
import { useSetError } from "./error-provider";
+import { useStoreValue } from "./settings";
const AccountContext = createContext<{
apiUrl: string;
@@ -31,22 +34,19 @@ export const AccountProvider = ({
}
const setError = useSetError();
-
- const [accStr] = useMMKVString("accounts");
- const accounts = accStr ? z.array(AccountP).parse(JSON.parse(accStr)) : null;
+ const accounts = useStoreValue("accounts", z.array(AccountP)) ?? [];
const ret = useMemo(() => {
const acc = accounts.find((x) => x.selected);
return {
- apiUrl: acc.apiUrl,
- authToken: acc.token,
+ apiUrl: Platform.OS === "web" ? "/api" : acc?.apiUrl,
+ authToken: acc?.token,
selectedAccount: acc,
- accounts:
- accounts?.map((account) => ({
- ...account,
- select: () => updateAccount(account.id, { ...account, selected: true }),
- remove: () => removeAccounts((x) => x.id === account.id),
- })) ?? [],
+ accounts: accounts.map((account) => ({
+ ...account,
+ select: () => updateAccount(account.id, { ...account, selected: true }),
+ remove: () => removeAccounts((x) => x.id === account.id),
+ })),
};
}, [accounts]);
@@ -62,10 +62,10 @@ export const AccountProvider = ({
path: ["auth", "me"],
parser: UserP,
placeholderData: ret.selectedAccount,
- enabled: ret.selectedAccount,
+ enabled: !!ret.selectedAccount,
options: {
apiUrl: ret.apiUrl,
- authToken: ret.authToken,
+ authToken: ret.authToken?.access_token,
},
});
// Use a ref here because we don't want the effect to trigger when the selected
diff --git a/front/src/providers/account-store.ts b/front/src/providers/account-store.ts
new file mode 100644
index 00000000..32a02224
--- /dev/null
+++ b/front/src/providers/account-store.ts
@@ -0,0 +1,58 @@
+import { Platform } from "react-native";
+import { z } from "zod";
+import { type Account, AccountP } from "~/models";
+import { readValue, setCookie, storeValue } from "./settings";
+
+const writeAccounts = (accounts: Account[]) => {
+ storeValue("accounts", accounts);
+ if (Platform.OS === "web") {
+ const selected = accounts.find((x) => x.selected);
+ if (!selected) return;
+ setCookie("account", selected);
+ // cookie used for images and videos since we can't add Authorization headers in img or video tags.
+ setCookie("X-Bearer", selected?.token.access_token);
+ }
+};
+
+export const addAccount = (account: Account) => {
+ const accounts = readValue("accounts", z.array(AccountP)) ?? [];
+
+ // Prevent the user from adding the same account twice.
+ if (accounts.find((x) => x.id === account.id)) {
+ updateAccount(account.id, account);
+ return;
+ }
+
+ for (const acc of accounts) acc.selected = false;
+ account.selected = true;
+ accounts.push(account);
+ writeAccounts(accounts);
+};
+
+export const removeAccounts = (filter: (acc: Account) => boolean) => {
+ let accounts = readValue("accounts", z.array(AccountP)) ?? [];
+ accounts = accounts.filter((x) => !filter(x));
+ if (!accounts.find((x) => x.selected) && accounts.length > 0) {
+ accounts[0].selected = true;
+ }
+ writeAccounts(accounts);
+};
+
+export const updateAccount = (id: string, account: Account) => {
+ const accounts = readValue("accounts", z.array(AccountP)) ?? [];
+ const idx = accounts.findIndex((x) => x.id === id);
+ if (idx === -1) return;
+
+ const selected = account.selected;
+ if (selected) {
+ for (const acc of accounts) acc.selected = false;
+ // if account was already on the accounts list, we keep it selected.
+ account.selected = selected;
+ } else if (accounts[idx].selected) {
+ // we just unselected the current account, focus another one.
+ if (accounts.length > 0) accounts[0].selected = true;
+ }
+
+ accounts[idx] = account;
+ writeAccounts(accounts);
+};
diff --git a/front/src/providers/index.tsx b/front/src/providers/index.tsx
index ff22dc68..0263fc63 100644
--- a/front/src/providers/index.tsx
+++ b/front/src/providers/index.tsx
@@ -4,6 +4,7 @@ import { type ReactNode, useState } from "react";
import { ThemeSelector } from "~/primitives/theme";
import { createQueryClient } from "~/query";
import { ErrorConsumer, ErrorProvider } from "./error-provider";
+import { AccountProvider } from "./account-provider";
const QueryProvider = ({ children }: { children: ReactNode }) => {
const [queryClient] = useState(() => createQueryClient());
@@ -26,7 +27,9 @@ export const Providers = ({ children }: { children: ReactNode }) => {
- {children}
+
+ {children}
+
diff --git a/front/src/providers/settings.ts b/front/src/providers/settings.ts
index 183929de..bf93b4fe 100644
--- a/front/src/providers/settings.ts
+++ b/front/src/providers/settings.ts
@@ -1,7 +1,7 @@
import { MMKV, useMMKVString } from "react-native-mmkv";
-import type { ZodTypeAny } from "zod";
+import type { ZodTypeAny, z } from "zod";
-export const storage = new MMKV();
+const storage = new MMKV();
function toBase64(utf8: string) {
if (typeof window !== "undefined") return window.btoa(utf8);
@@ -35,11 +35,21 @@ export const readCookie = (
const ret = ca.find((x) => x.trimStart().startsWith(name));
if (ret === undefined) return undefined;
const str = fromBase64(ret.substring(name.length));
- return parser ? parser.parse(JSON.parse(str)) : str;
+ return parser ? (parser.parse(JSON.parse(str)) as z.infer) : str;
};
-export const useStoreValue = (key: string, parser?: T) => {
+export const useStoreValue = (key: string, parser: T) => {
const [val] = useMMKVString(key);
- if (!val) return val;
- return parser ? parser.parse(JSON.parse(val)) : val;
+ if (val === undefined) return val;
+ return parser.parse(JSON.parse(val)) as z.infer;
+};
+
+export const storeValue = (key: string, value: unknown) => {
+ storage.set(key, JSON.stringify(value));
+};
+
+export const readValue = (key: string, parser: T) => {
+ const val = storage.getString(key);
+ if (val === undefined) return val;
+ return parser.parse(JSON.parse(val)) as z.infer;
};