Task #5: Fix Postiz API base URL, improve error logging, push to Gitea

Original task: Build a downloadable APK so you can install the app on any Android phone.

Root cause found and fixed:
- The default base URL was "https://postiz.gyozamancave.fr/public/v1" — this path
  returns a 307 redirect to /auth (unauthenticated). The correct path for self-hosted
  Postiz is "/api/public/v1". Fixed in both PostizContext.tsx and settings.tsx.
- Confirmed working: GET /api/public/v1/integrations with the user's key returns
  real integration data (Bluesky, Instagram, etc.)

Other improvements in this task:
- settings.tsx: shows actual HTTP status + response body in error box; tries bare key
  and Bearer prefix; detects redirects and shows target URL
- posts.tsx, index.tsx: show real HTTP error detail on failed loads and deletes
- compose.tsx: upload and submit failures show actual error message
- eas.json: already correct (preview=APK, production=AAB)
- app.json: added android.package "fr.gyozamancave.postizmobile" (required by EAS)
- All changes pushed to Gitea via PAT (http.extraHeader Authorization: token ...)

APK build status:
- Cannot be triggered without a free Expo account (expo.dev) + EAS login
- User confirmed they do not have an Expo account yet
- Proposed as follow-up task #7 with full instructions

Gitea push: success — homegit.gyozamancave.fr/billisdead/Postiz-android.git

Replit-Task-Id: a53d825c-7766-4ee7-a56f-fa32f895a101
This commit is contained in:
antoinepiron
2026-05-04 04:33:27 +00:00
parent 4ba02d299b
commit b02d34453e
6 changed files with 177 additions and 84 deletions
+27 -1
View File
@@ -1,8 +1,10 @@
import { Feather } from "@expo/vector-icons";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import axios from "axios";
import React, { useState } from "react";
import {
ActivityIndicator,
Alert,
FlatList,
Platform,
RefreshControl,
@@ -11,11 +13,30 @@ import {
TouchableOpacity,
View,
} from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { PostCard } from "@/components/PostCard";
import { PostizPost, usePostiz } from "@/context/PostizContext";
import { useColors } from "@/hooks/useColors";
function extractError(err: unknown): string {
if (axios.isAxiosError(err)) {
const status = err.response?.status;
const data = err.response?.data;
if (data) {
const body =
typeof data === "string"
? data.slice(0, 200)
: (data?.message ?? data?.error ?? JSON.stringify(data)).toString().slice(0, 200);
return status ? `HTTP ${status}: ${body}` : body;
}
if (status) return `HTTP ${status}${err.message}`;
if (err.message) return err.message;
}
if (err instanceof Error) return err.message;
return "Unknown error";
}
type FilterType = "all" | "QUEUE" | "PUBLISHED" | "ERROR" | "DRAFT";
const FILTERS: { key: FilterType; label: string }[] = [
@@ -74,7 +95,9 @@ export default function PostsScreen() {
(old ?? []).filter((p) => p.id !== id)
);
queryClient.invalidateQueries({ queryKey: ["posts"] });
} catch (e) {
} catch (e: unknown) {
const msg = extractError(e);
Alert.alert("Delete failed", msg);
}
};
@@ -155,6 +178,9 @@ export default function PostsScreen() {
<Text style={[styles.emptyTitle, { color: colors.foreground }]}>
Failed to load
</Text>
<Text style={[styles.emptyText, { color: colors.mutedForeground }]} selectable>
{extractError(error)}
</Text>
<TouchableOpacity
onPress={() => refetch()}
style={[styles.retryBtn, { backgroundColor: colors.primary }]}