Spaces:
Sleeping
Sleeping
File size: 1,810 Bytes
eddc354 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | /**
* Обратная связь от пользователей («чего не хватает»).
* Сейчас всё хранится в localStorage.
* SUPABASE: заменить на таблицу `feedback` (insert для user, select для admin).
*/
export type FeedbackItem = {
id: string;
userId: string;
username: string;
text: string;
createdAt: number;
read: boolean;
};
export const FEEDBACK_KEY = "realknot-feedback-v1";
const safe = <T,>(fn: () => T, fallback: T): T => {
try {
return fn();
} catch {
return fallback;
}
};
const newId = () => Math.random().toString(36).slice(2, 10);
/** SUPABASE: `supabase.from("feedback").select("*").order("created_at")`. */
export const listFeedback = (): FeedbackItem[] =>
safe(() => {
const raw = localStorage.getItem(FEEDBACK_KEY);
const arr = raw ? (JSON.parse(raw) as FeedbackItem[]) : [];
return arr.sort((a, b) => b.createdAt - a.createdAt);
}, []);
const write = (list: FeedbackItem[]) =>
safe(() => localStorage.setItem(FEEDBACK_KEY, JSON.stringify(list)), undefined);
/** SUPABASE: `supabase.from("feedback").insert({ ... })`. */
export const addFeedback = (userId: string, username: string, text: string) => {
const item: FeedbackItem = {
id: newId(),
userId,
username,
text: text.trim(),
createdAt: Date.now(),
read: false,
};
write([item, ...listFeedback()]);
return item;
};
export const markFeedbackRead = (id: string) => {
write(listFeedback().map((f) => (f.id === id ? { ...f, read: true } : f)));
return listFeedback();
};
export const removeFeedback = (id: string) => {
write(listFeedback().filter((f) => f.id !== id));
return listFeedback();
};
export const unreadFeedbackCount = () => listFeedback().filter((f) => !f.read).length;
|