Spaces:
Sleeping
Sleeping
| /** | |
| * Обратная связь от пользователей («чего не хватает»). | |
| * Сейчас всё хранится в 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; | |