Files
Postiz-android/artifacts/postiz-mobile/context/PostizContext.tsx
T
billisdead 20ca6e0334
Release APK / build (push) Has been cancelled
feat(compose): group channels by customer with tap-to-select-all
Channels in the compose picker are now grouped by customer (as returned
by the Postiz API). Tapping a customer header selects or deselects all
its channels at once. Individual channel chips still toggle as before.
Workspace header is hidden when only one workspace is configured.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 21:54:49 +02:00

190 lines
5.2 KiB
TypeScript

import axios, { AxiosInstance } from "axios";
import * as SecureStore from "expo-secure-store";
import React, {
createContext,
useCallback,
useContext,
useEffect,
useState,
} from "react";
const WORKSPACES_KEY = "postiz_workspaces_v2";
const LEGACY_API_KEY = "postiz_api_key";
const LEGACY_BASE_URL = "postiz_base_url";
export const DEFAULT_BASE_URL = "https://postiz.gyozamancave.fr/api/public/v1";
export interface PostizWorkspace {
id: string;
name: string;
apiKey: string;
baseUrl: string;
}
export interface PostizIntegration {
id: string;
name: string;
type: string;
picture?: string;
identifier?: string;
internalType?: string;
customer?: { id: string; name: string };
}
export interface PostizMediaItem {
id: string;
path: string;
}
export interface PostizPost {
id: string;
content: string;
state: "QUEUE" | "PUBLISHED" | "ERROR" | "DRAFT";
publishDate: string;
integration?: PostizIntegration;
integrations?: PostizIntegration[];
image?: PostizMediaItem[];
group?: string;
errorMessage?: string;
}
export interface PostizUploadResult {
id: string;
path: string;
}
interface PostizContextValue {
workspaces: PostizWorkspace[];
isConfigured: boolean;
isLoading: boolean;
clients: Record<string, AxiosInstance>;
addWorkspace: (ws: Omit<PostizWorkspace, "id">) => Promise<void>;
updateWorkspace: (ws: PostizWorkspace) => Promise<void>;
removeWorkspace: (id: string) => Promise<void>;
// backward compat for posts.tsx (first workspace)
client: AxiosInstance | null;
apiKey: string;
baseUrl: string;
}
const PostizContext = createContext<PostizContextValue>({
workspaces: [],
isConfigured: false,
isLoading: true,
clients: {},
addWorkspace: async () => {},
updateWorkspace: async () => {},
removeWorkspace: async () => {},
client: null,
apiKey: "",
baseUrl: DEFAULT_BASE_URL,
});
function makeClient(ws: PostizWorkspace): AxiosInstance {
const baseURL = ws.baseUrl.endsWith("/") ? ws.baseUrl : ws.baseUrl + "/";
const instance = axios.create({
baseURL,
headers: { Authorization: ws.apiKey, "Content-Type": "application/json" },
timeout: 15000,
});
instance.interceptors.request.use((config) => {
console.log(">>> REQUEST:", config.method?.toUpperCase(), (config.baseURL ?? "") + (config.url ?? ""));
return config;
});
return instance;
}
function buildClients(list: PostizWorkspace[]): Record<string, AxiosInstance> {
return Object.fromEntries(list.map((ws) => [ws.id, makeClient(ws)]));
}
export function PostizProvider({ children }: { children: React.ReactNode }) {
const [workspaces, setWorkspaces] = useState<PostizWorkspace[]>([]);
const [clients, setClients] = useState<Record<string, AxiosInstance>>({});
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
(async () => {
try {
const stored = await SecureStore.getItemAsync(WORKSPACES_KEY);
if (stored) {
const list: PostizWorkspace[] = JSON.parse(stored);
setWorkspaces(list);
setClients(buildClients(list));
} else {
// Migrate legacy single-workspace config
const legacyKey = await SecureStore.getItemAsync(LEGACY_API_KEY);
const legacyUrl = await SecureStore.getItemAsync(LEGACY_BASE_URL);
if (legacyKey) {
const migrated: PostizWorkspace = {
id: Date.now().toString(),
name: "Default",
apiKey: legacyKey,
baseUrl: (legacyUrl || DEFAULT_BASE_URL).replace(/\/$/, ""),
};
const list = [migrated];
await SecureStore.setItemAsync(WORKSPACES_KEY, JSON.stringify(list));
setWorkspaces(list);
setClients(buildClients(list));
}
}
} catch {
} finally {
setIsLoading(false);
}
})();
}, []);
const persist = useCallback(async (list: PostizWorkspace[]) => {
await SecureStore.setItemAsync(WORKSPACES_KEY, JSON.stringify(list));
setWorkspaces(list);
setClients(buildClients(list));
}, []);
const addWorkspace = useCallback(
async (ws: Omit<PostizWorkspace, "id">) => {
await persist([...workspaces, { ...ws, id: Date.now().toString() }]);
},
[workspaces, persist]
);
const updateWorkspace = useCallback(
async (ws: PostizWorkspace) => {
await persist(workspaces.map((w) => (w.id === ws.id ? ws : w)));
},
[workspaces, persist]
);
const removeWorkspace = useCallback(
async (id: string) => {
await persist(workspaces.filter((w) => w.id !== id));
},
[workspaces, persist]
);
const primaryWorkspace = workspaces[0] ?? null;
return (
<PostizContext.Provider
value={{
workspaces,
isConfigured: workspaces.length > 0,
isLoading,
clients,
addWorkspace,
updateWorkspace,
removeWorkspace,
client: primaryWorkspace ? (clients[primaryWorkspace.id] ?? null) : null,
apiKey: primaryWorkspace?.apiKey ?? "",
baseUrl: primaryWorkspace?.baseUrl ?? DEFAULT_BASE_URL,
}}
>
{children}
</PostizContext.Provider>
);
}
export function usePostiz() {
return useContext(PostizContext);
}