fix: align POST /posts payload with Postiz public API v1 format

Switch from deprecated content/integrations structure to posts[] array
with integration.id and value[] fields. Add required shortLink and tags
fields. Use globalThis.fetch instead of axios for the POST request.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-16 21:09:28 +02:00
parent 5994be5ddc
commit da31d47061
+31 -20
View File
@@ -1,6 +1,5 @@
import { Feather } from "@expo/vector-icons"; import { Feather } from "@expo/vector-icons";
import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useQuery, useQueryClient } from "@tanstack/react-query";
import axios from "axios";
import DateTimePicker from "@react-native-community/datetimepicker"; import DateTimePicker from "@react-native-community/datetimepicker";
import * as Haptics from "expo-haptics"; import * as Haptics from "expo-haptics";
import { Image } from "expo-image"; import { Image } from "expo-image";
@@ -111,7 +110,7 @@ export default function ComposeScreen() {
}; };
const handleSubmit = async () => { const handleSubmit = async () => {
if (!client) return; if (!isConfigured) return;
if (!content.trim()) { if (!content.trim()) {
Alert.alert("Empty post", "Please write something before posting."); Alert.alert("Empty post", "Please write something before posting.");
return; return;
@@ -130,18 +129,39 @@ export default function ComposeScreen() {
media = [{ id: uploaded.id, path: uploaded.path }]; media = [{ id: uploaded.id, path: uploaded.path }];
} }
} }
const contentItem: { content: string; image?: Array<{ id: string; path: string }> } = {
content: content.trim(),
};
if (media.length > 0) contentItem.image = media;
const payload = { const payload = {
type: postNow ? "now" : "schedule", type: postNow ? "now" : "schedule",
date: postNow ? new Date().toISOString() : scheduleDate.toISOString(), date: postNow ? new Date().toISOString() : scheduleDate.toISOString(),
content: [contentItem], shortLink: false,
integrations: selectedChannels, tags: [] as string[],
posts: selectedChannels.map((integrationId) => ({
integration: { id: integrationId },
value: [{ content: content.trim(), id: "", image: media }],
})),
}; };
await client.post("posts", payload); const body = JSON.stringify(payload);
// eslint-disable-next-line no-undef
const res = await globalThis.fetch(`${baseUrl}/posts`, {
method: "POST",
headers: {
Authorization: apiKey,
"Content-Type": "application/json",
},
body,
});
if (!res.ok) {
let detail = "";
try {
const raw = await res.text();
detail = raw.slice(0, 300);
} catch {
detail = res.statusText;
}
throw new Error(`HTTP ${res.status}: ${detail}`);
}
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
Alert.alert( Alert.alert(
"Posted!", "Posted!",
@@ -152,16 +172,7 @@ export default function ComposeScreen() {
queryClient.invalidateQueries({ queryKey: ["posts-list"] }); queryClient.invalidateQueries({ queryKey: ["posts-list"] });
} catch (e: unknown) { } catch (e: unknown) {
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error); Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
let msg = "Could not submit post."; const msg = e instanceof Error ? e.message : "Could not submit post.";
if (axios.isAxiosError(e)) {
const data = e.response?.data;
const detail = data
? (typeof data === "string" ? data : (data?.message ?? data?.error ?? JSON.stringify(data))).toString().slice(0, 300)
: e.message;
msg = `HTTP ${e.response?.status ?? "?"}: ${detail}`;
} else if (e instanceof Error) {
msg += `\n${e.message}`;
}
Alert.alert("Failed", msg); Alert.alert("Failed", msg);
} finally { } finally {
setSubmitting(false); setSubmitting(false);