Make posts appear in feed
This commit is contained in:
parent
187bc6fde2
commit
e35464dcfa
|
@ -8,7 +8,7 @@ import outgoingMessagesReducer from "../features/outgoingMessages/outgoingMessag
|
||||||
import linkReducer from "../features/link/linkSlice";
|
import linkReducer from "../features/link/linkSlice";
|
||||||
import accountPageReducer from "../features/accountPage/accountPageSlice";
|
import accountPageReducer from "../features/accountPage/accountPageSlice";
|
||||||
|
|
||||||
export default configureStore({
|
const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
user: userReducer,
|
user: userReducer,
|
||||||
currentUser: currentUserReducer,
|
currentUser: currentUserReducer,
|
||||||
|
@ -20,3 +20,17 @@ export default configureStore({
|
||||||
accountPage: accountPageReducer,
|
accountPage: accountPageReducer,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (import.meta.env.DEV) {
|
||||||
|
store.subscribe(() => {
|
||||||
|
const s = store.getState();
|
||||||
|
|
||||||
|
console.log("[DEBUG] users:", s.users);
|
||||||
|
|
||||||
|
console.log("[DEBUG] currentUser:", s.currentUser);
|
||||||
|
|
||||||
|
console.log("[DEBUG] posts:", s.posts);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default store;
|
||||||
|
|
|
@ -22,7 +22,7 @@ import { currentUserUpdated } from "../features/currentUser/currentUserSlice";
|
||||||
|
|
||||||
import { usersUpdated } from "../features/users/usersSlice";
|
import { usersUpdated } from "../features/users/usersSlice";
|
||||||
|
|
||||||
import { postsUpdated } from "../features/posts/postsSlice";
|
import { postsLoaded, postsUpdated } from "../features/posts/postsSlice";
|
||||||
|
|
||||||
import { incomingMessagesUpdated } from "../features/incomingMessages/incomingMessagesSlice";
|
import { incomingMessagesUpdated } from "../features/incomingMessages/incomingMessagesSlice";
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@ const LOGIN_URL = `${API_BASE}/login`;
|
||||||
|
|
||||||
const USERS_URL = `${API_BASE}/users`;
|
const USERS_URL = `${API_BASE}/users`;
|
||||||
|
|
||||||
|
const POSTS_URL = `${API_BASE}/posts`;
|
||||||
|
|
||||||
const LS_TOKEN = "fakebook.jwt";
|
const LS_TOKEN = "fakebook.jwt";
|
||||||
|
|
||||||
const LS_USER_ID = "fakebook.user_id";
|
const LS_USER_ID = "fakebook.user_id";
|
||||||
|
@ -149,6 +151,16 @@ export function subscribeAuth() {
|
||||||
isEmailVerified: !!u.isEmailVerified,
|
isEmailVerified: !!u.isEmailVerified,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
// cold-start: get the full feed once
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
subscribePosts(); // <—— fetches /posts and dispatches postsLoaded
|
||||||
|
|
||||||
|
currentUserOnline(); // mark myself online immediately
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn("[Auth] subscribeAuth failed:", err.message);
|
console.warn("[Auth] subscribeAuth failed:", err.message);
|
||||||
|
|
||||||
|
@ -229,6 +241,8 @@ export async function signInUser(user) {
|
||||||
);
|
);
|
||||||
|
|
||||||
store.dispatch(errorOccured(""));
|
store.dispatch(errorOccured(""));
|
||||||
|
|
||||||
|
currentUserOnline(); // mark myself online immediately
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
store.dispatch(errorOccured(err.message));
|
store.dispatch(errorOccured(err.message));
|
||||||
|
|
||||||
|
@ -314,6 +328,14 @@ function openSocket() {
|
||||||
hub.on("fakebook.users.put", (raw) => {
|
hub.on("fakebook.users.put", (raw) => {
|
||||||
store.dispatch(usersUpdated([parseMsg(raw)]));
|
store.dispatch(usersUpdated([parseMsg(raw)]));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
hub.on("fakebook.posts.post", (raw) =>
|
||||||
|
store.dispatch(postsUpdated([JSON.parse(raw)]))
|
||||||
|
);
|
||||||
|
|
||||||
|
hub.on("fakebook.posts.put", (raw) =>
|
||||||
|
store.dispatch(postsUpdated([JSON.parse(raw)]))
|
||||||
|
);
|
||||||
})
|
})
|
||||||
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
@ -510,21 +532,36 @@ export function subscribeUsers() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------- posts ------------------------------------- */
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/* posts subscription: replaces old in-memory mock version */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
export function subscribePosts() {
|
export function subscribePosts() {
|
||||||
setTimeout(() => {
|
let cancelled = false;
|
||||||
store.dispatch(
|
|
||||||
postsUpdated(
|
|
||||||
DB.posts.map((p) => ({
|
|
||||||
...p,
|
|
||||||
timestamp: new Date(p.timestamp).toLocaleString(),
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
return () => {};
|
(async () => {
|
||||||
|
try {
|
||||||
|
const token = localStorage.getItem(LS_TOKEN);
|
||||||
|
|
||||||
|
const arr = await $fetch(`${POSTS_URL}?limit=-1`, {
|
||||||
|
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!cancelled) {
|
||||||
|
store.dispatch(postsLoaded(arr)); // full list once
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("[subscribePosts] failed:", err.message);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* return unsubscribe fn (keeps contract identical) */
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function upload(post) {
|
export async function upload(post) {
|
||||||
|
|
|
@ -1,17 +1,65 @@
|
||||||
import { createSlice } from "@reduxjs/toolkit";
|
import { createSlice } from "@reduxjs/toolkit";
|
||||||
|
|
||||||
|
import mapRestPost from "../../utils/mapRestPost";
|
||||||
|
|
||||||
export const postsSlice = createSlice({
|
export const postsSlice = createSlice({
|
||||||
name: "posts",
|
name: "posts",
|
||||||
initialState: [],
|
|
||||||
|
initialState: [], // still an array
|
||||||
|
|
||||||
reducers: {
|
reducers: {
|
||||||
|
/* full reload (initial screen) --------------------------------- */
|
||||||
|
|
||||||
|
postsLoaded: (_, action) => action.payload.map(mapRestPost),
|
||||||
|
|
||||||
|
/* incremental updates: insert new or patch existing ------------ */
|
||||||
|
|
||||||
postsUpdated: (state, action) => {
|
postsUpdated: (state, action) => {
|
||||||
const updatedState = [];
|
const incoming = action.payload; // array of raw rows
|
||||||
action.payload.forEach((post) => updatedState.push(post));
|
|
||||||
return updatedState;
|
incoming.forEach((raw) => {
|
||||||
|
const postID = raw.post_id ?? raw.postID;
|
||||||
|
|
||||||
|
const idx = state.findIndex((p) => p.postID === postID);
|
||||||
|
|
||||||
|
if (idx === -1) {
|
||||||
|
/* NEW */
|
||||||
|
|
||||||
|
state.push(mapRestPost(raw));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MERGE PARTIAL UPDATE */
|
||||||
|
|
||||||
|
const cur = state[idx];
|
||||||
|
|
||||||
|
const next = { ...cur };
|
||||||
|
|
||||||
|
if (raw.text !== undefined) next.text = raw.text;
|
||||||
|
|
||||||
|
if (raw.photoURL !== undefined) next.photoURL = raw.photoURL;
|
||||||
|
|
||||||
|
if (raw.youtubeURL !== undefined) next.youtubeURL = raw.youtubeURL;
|
||||||
|
|
||||||
|
if (raw.isPhoto !== undefined) next.isPhoto = !!raw.isPhoto;
|
||||||
|
|
||||||
|
if (raw.isYoutube !== undefined) next.isYoutube = !!raw.isYoutube;
|
||||||
|
|
||||||
|
if (raw.comments !== undefined)
|
||||||
|
next.comments = JSON.parse(raw.comments);
|
||||||
|
|
||||||
|
if (raw.likes !== undefined) next.likes = JSON.parse(raw.likes);
|
||||||
|
|
||||||
|
if (raw.timestamp !== undefined)
|
||||||
|
next.timestamp = new Date(raw.timestamp);
|
||||||
|
|
||||||
|
state[idx] = next;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const { postsUpdated } = postsSlice.actions;
|
export const { postsLoaded, postsUpdated } = postsSlice.actions;
|
||||||
|
|
||||||
export default postsSlice.reducer;
|
export default postsSlice.reducer;
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* Converts the “Magic / Firebase” row into the shape the UI expects.
|
||||||
|
|
||||||
|
– comments / likes arrive as JSON-encoded strings
|
||||||
|
|
||||||
|
– timestamp comes as “2025-03-18 14:18:43” (UTC); we store it as Date
|
||||||
|
|
||||||
|
– isPhoto / isYoutube arrive as 0|1 (or false|true) → boolean
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default function mapRestPost(row) {
|
||||||
|
/* helper – coerce all falsy / 0 / "0" / false values to boolean */
|
||||||
|
|
||||||
|
const bool = (v) => v === true || v === 1 || v === "1";
|
||||||
|
|
||||||
|
return {
|
||||||
|
postID: row.post_id,
|
||||||
|
|
||||||
|
userID: row.user_id,
|
||||||
|
|
||||||
|
text: row.text,
|
||||||
|
|
||||||
|
photoURL: row.photoURL,
|
||||||
|
|
||||||
|
youtubeURL: row.youtubeURL,
|
||||||
|
|
||||||
|
isPhoto: bool(row.isPhoto),
|
||||||
|
|
||||||
|
isYoutube: bool(row.isYoutube),
|
||||||
|
|
||||||
|
comments: JSON.parse(row.comments || "[]"),
|
||||||
|
|
||||||
|
likes: JSON.parse(row.likes || "[]"),
|
||||||
|
|
||||||
|
/* keep the original ISO string too if you need it elsewhere */
|
||||||
|
|
||||||
|
timestamp: new Date(row.timestamp).toLocaleString(),
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue