Make user able to create new posts

This commit is contained in:
Alex Erdei 2025-05-04 17:16:24 +01:00
parent d491871126
commit c6e937f79f
2 changed files with 84 additions and 39 deletions

View File

@ -552,19 +552,58 @@ export function subscribePosts() {
cancelled = true; cancelled = true;
}; };
} }
/* ------------------------------------------------------------------ */
/* CREATE A NEW POST uses in-memory auth + sends post_id */
/* ------------------------------------------------------------------ */
export async function upload(post) { export async function upload(post) {
await delay(); /* fast path: in-memory → fall back to localStorage once */
const doc = { ...post, postID: genId(), timestamp: nowISO() }; const token = authToken || localStorage.getItem(LS_TOKEN);
DB.posts.unshift(doc); const user_id = authUser || localStorage.getItem(LS_USER_ID);
if (me()) me().posts.unshift(doc.postID); if (!token || !user_id) throw new Error("Not authenticated");
persist(); /* Magic table requires the primary key up front */
return { id: doc.postID }; const post_id = genId(); // already in backend.js
const body = {
post_id, // ← fixes NOT NULL error
user_id,
text: post.text ?? "",
photoURL: post.photoURL ?? "",
youtubeURL: post.youtubeURL ?? "",
isPhoto: post.isPhoto ? 1 : 0, // Magic expects 1/0
isYoutube: post.isYoutube ? 1 : 0,
likes: JSON.stringify(post.likes ?? []),
comments: JSON.stringify(post.comments ?? []),
timestamp: new Date().toISOString(), // optional but useful
};
/* POST /posts let SignalR broadcast the newly created row */
await $fetch(POSTS_URL, {
method: "POST",
body: JSON.stringify(body),
}); // $fetch adds Authorization
/* keep old contract: caller expects { id } */
return { id: post_id };
} }
/* -------------------------------------------------------------- /* --------------------------------------------------------------

View File

@ -2,59 +2,65 @@ import { createSlice } from "@reduxjs/toolkit";
import mapRestPost from "../../utils/mapRestPost"; import mapRestPost from "../../utils/mapRestPost";
/* --------------------------------------------------------------
helper fixes the Magic placeholder only once, on INSERT
-------------------------------------------------------------- */
const withValidTimestamp = (post) =>
post.timestamp === "Invalid Date" || !post.timestamp
? { ...post, timestamp: new Date().toISOString() }
: post;
export const postsSlice = createSlice({ export const postsSlice = createSlice({
name: "posts", name: "posts",
initialState: [], initialState: [],
reducers: { reducers: {
/* full reload (initial screen) --------------------------------- */ /* full reload: oldest → newest, so reverse once */
postsLoaded: (_state, action) => postsLoaded: (_state, action) => action.payload.map(mapRestPost).reverse(),
// API returns oldest → newest, so reverse once
action.payload.map(mapRestPost).reverse(), /* incremental updates from Signal R */
/* incremental updates: insert new or patch existing ------------ */ postsUpdated: (state, action) => {
action.payload.forEach((raw) => {
const postID = raw.post_id ?? raw.postID;
postsUpdated: (state, action) => { const idx = state.findIndex((p) => p.postID === postID);
const incoming = action.payload; // array of raw rows
incoming.forEach((raw) => { /* -------- INSERT NEW ------------------------------------------------ */
const postID = raw.post_id ?? raw.postID;
const idx = state.findIndex((p) => p.postID === postID); if (idx === -1) {
state.unshift(withValidTimestamp(mapRestPost(raw))); // newest first
if (idx === -1) { return;
/* NEW → put at the front so list stays newest-first */ }
state.unshift(mapRestPost(raw)); /* -------- MERGE PARTIAL UPDATE ------------------------------------- */
return; const cur = state[idx];
}
/* MERGE PARTIAL UPDATE (order unchanged) ------------------ */ if (raw.text !== undefined) cur.text = raw.text;
const cur = state[idx]; if (raw.photoURL !== undefined) cur.photoURL = raw.photoURL;
if (raw.text !== undefined) cur.text = raw.text; if (raw.youtubeURL !== undefined) cur.youtubeURL = raw.youtubeURL;
if (raw.photoURL !== undefined) cur.photoURL = raw.photoURL; if (raw.isPhoto !== undefined) cur.isPhoto = !!raw.isPhoto;
if (raw.youtubeURL !== undefined) cur.youtubeURL = raw.youtubeURL; if (raw.isYoutube !== undefined) cur.isYoutube = !!raw.isYoutube;
if (raw.isPhoto !== undefined) cur.isPhoto = !!raw.isPhoto; if (raw.comments !== undefined) cur.comments = JSON.parse(raw.comments);
if (raw.isYoutube !== undefined) cur.isYoutube = !!raw.isYoutube; if (raw.likes !== undefined) cur.likes = JSON.parse(raw.likes);
if (raw.comments !== undefined) cur.comments = JSON.parse(raw.comments); /* raw.timestamp never changes in an update → leave untouched */
});
if (raw.likes !== undefined) cur.likes = JSON.parse(raw.likes); },
},
/* raw.timestamp never changes, so we leave it untouched */
});
},
},
}); });
export const { postsLoaded, postsUpdated } = postsSlice.actions; export const { postsLoaded, postsUpdated } = postsSlice.actions;