fix(mobile): replace 404 media library error with session-required state and device gallery fallback
Release APK / build (push) Has been cancelled

The Postiz public API v1 does not expose a media listing endpoint.
Switch URL to the correct internal path (/media?page=0&search=), handle
the resulting 401 with a dedicated lock-icon state, and wire the existing
device gallery picker as an onPickFromDevice fallback so the modal stays
usable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 19:08:15 +02:00
parent 0cf5800463
commit fb64b671d0
2 changed files with 32 additions and 5 deletions
@@ -767,6 +767,7 @@ export default function ComposeScreen() {
workspaces={workspaces}
maxSelect={MAX_IMAGES - mediaItems.length}
onClose={() => setShowMediaLibrary(false)}
onPickFromDevice={() => { setShowMediaLibrary(false); pickImage(); }}
onSelect={(items: LibraryMediaItem[]) => {
setMediaItems((prev) =>
[
@@ -35,6 +35,7 @@ interface Props {
maxSelect: number;
onClose: () => void;
onSelect: (items: LibraryMediaItem[]) => void;
onPickFromDevice?: () => void;
}
function resolveUrl(path: string, baseUrl: string): string {
@@ -43,7 +44,7 @@ function resolveUrl(path: string, baseUrl: string): string {
return `${origin}/${path.replace(/^\//, "")}`;
}
export function MediaLibraryModal({ visible, workspaces, defaultWorkspaceId, maxSelect, onClose, onSelect }: Props) {
export function MediaLibraryModal({ visible, workspaces, defaultWorkspaceId, maxSelect, onClose, onSelect, onPickFromDevice }: Props) {
const colors = useColors();
const insets = useSafeAreaInsets();
const [activeId, setActiveId] = useState<string>("");
@@ -66,17 +67,19 @@ export function MediaLibraryModal({ visible, workspaces, defaultWorkspaceId, max
if (!activeWorkspace) return;
setLoading(true);
setError(null);
const url = `${activeWorkspace.baseUrl}/media`;
const apiBase = activeWorkspace.baseUrl.replace(/\/public\/v1$/, "");
const url = `${apiBase}/media?page=0&search=`;
try {
// eslint-disable-next-line no-undef
const res = await globalThis.fetch(url, {
headers: { Authorization: activeWorkspace.apiKey },
});
if (!res.ok) {
if (res.status === 401 || res.status === 403) {
throw new Error("SESSION_REQUIRED");
}
if (res.status === 404) {
throw new Error(
`Media listing endpoint not found (404).\nURL tried: ${url}\n\nThis feature requires Postiz to expose GET /media in its public API. Your version may not support it yet.`
);
throw new Error("ENDPOINT_NOT_FOUND");
}
throw new Error(`HTTP ${res.status}${url}`);
}
@@ -171,6 +174,29 @@ export function MediaLibraryModal({ visible, workspaces, defaultWorkspaceId, max
<View style={styles.centered}>
<ActivityIndicator color={colors.primary} size="large" />
</View>
) : error === "SESSION_REQUIRED" ? (
<View style={styles.centered}>
<Feather name="lock" size={28} color={colors.mutedForeground} />
<Text style={[styles.errorText, { color: colors.mutedForeground }]}>
{"Media library requires a web session.\nAPI key access is not supported by Postiz."}
</Text>
{onPickFromDevice && (
<TouchableOpacity
onPress={() => { onClose(); onPickFromDevice(); }}
style={[styles.retryBtn, { backgroundColor: colors.primary }]}
activeOpacity={0.8}
>
<Text style={[styles.retryText, { color: colors.primaryForeground }]}>Use device gallery</Text>
</TouchableOpacity>
)}
</View>
) : error === "ENDPOINT_NOT_FOUND" ? (
<View style={styles.centered}>
<Feather name="slash" size={28} color={colors.mutedForeground} />
<Text style={[styles.errorText, { color: colors.mutedForeground }]}>
{"Media library endpoint not found on this server."}
</Text>
</View>
) : error ? (
<View style={styles.centered}>
<Feather name="alert-circle" size={28} color={colors.error} />