SPB Git forge

spb/resto-ka

Public

Resto·Ka — tous les restaurants du Québec, menus complets et prix réels (famille ·Ka)

52commits 1branches 0releases
11.6 MBsize
maindefault branch
19 days agolast push
Python 69.3% TypeScript 16.7% CSS 7.9% JavaScript 4.7% HTML 1.4%
4.2 KB · 115 lines tsx
Raw Blame History
1// ==============================================================================2// Author: Simon-Pierre Boucher <contact@spboucher.ai>3// File:   favorites.tsx4// Desc:   Favoris ♥ « Mon univers Ka » — le hub Groupe KA (groupe-ka.com) est5//         le magasin central des favoris du groupe (aucun stockage local ni6//         navigateur) : lecture/écriture via l'API locale /api/favorites qui7//         relaie au hub. FavProvider charge la liste une fois ; FavButton =8//         cœur sur les cartes de restos et la fiche détail. Non connecté →9//         clic = « Se connecter avec KA ID ». Calqué sur foodka/favorites.tsx.10// ==============================================================================11import {12  ReactNode, createContext, useCallback, useContext,13  useEffect, useMemo, useState,14} from "react";15import { FavItem, Restaurant, fmtPrice, toggleFavorite } from "./api";1617interface FavState {18  ready: boolean;              // premier chargement terminé19  connected: boolean;          // session KA ID active20  ids: Set<string>;            // uid des restos en favoris21  items: FavItem[];22  toggle: (item: FavItem) => void;23}2425const FavContext = createContext<FavState>({26  ready: false, connected: false, ids: new Set(), items: [], toggle: () => {},27});2829/** Restaurant -> item de favori du hub (nom, ville, prix médian, image, url). */30export function restoFavItem(r: Restaurant): FavItem {31  const ms = r.menu_summary;32  return {33    item_id: r.uid,34    title: r.name || "Restaurant",35    subtitle: [r.city, r.region].filter(Boolean).join(" · ")36      || r.address || "",37    price_label: ms?.price_median != null38      ? `${fmtPrice(ms.price_median)} · plat médian`39      : (r.price_range || ""),40    image_url: ms?.image || (r.images ?? [])[1] || (r.images ?? [])[0] || "",41    url: `https://www.resto-ka.com/resto/${encodeURIComponent(r.uid)}`,42  };43}4445export function FavProvider({ children }: { children: ReactNode }) {46  const [ready, setReady] = useState(false);47  const [connected, setConnected] = useState(false);48  const [items, setItems] = useState<FavItem[]>([]);4950  useEffect(() => {51    fetch("/api/favorites", { credentials: "same-origin" })52      .then(async (res) => {53        if (res.status === 401) return;          // pas connecté : cœurs vides54        if (!res.ok) throw new Error(`API ${res.status}`);55        const data = (await res.json()) as { items?: FavItem[] };56        setConnected(true);57        setItems(data.items ?? []);58      })59      .catch(() => {})                            // hub muet : cœurs vides60      .finally(() => setReady(true));61  }, []);6263  const toggle = useCallback((item: FavItem) => {64    if (!connected) {65      // non connecté : passage par la connexion KA ID (hub Groupe KA)66      window.location.assign("/api/auth/ka/login");67      return;68    }69    const prev = items;70    const on = !prev.some((i) => i.item_id === item.item_id);71    // optimiste : le hub confirme (sinon on rétablit)72    setItems(on ? [...prev, item]73                : prev.filter((i) => i.item_id !== item.item_id));74    toggleFavorite(on, item).catch(() => setItems(prev));75  }, [connected, items]);7677  const ids = useMemo(78    () => new Set(items.map((i) => i.item_id)), [items]);7980  return (81    <FavContext.Provider value={{ ready, connected, ids, items, toggle }}>82      {children}83    </FavContext.Provider>84  );85}8687export const useFav = () => useContext(FavContext);8889/** Cœur ♥ — cartes de resto (par défaut) et fiche détail (`big`). */90export function FavButton({ r, big = false }: { r: Restaurant; big?: boolean }) {91  const { connected, ids, toggle } = useFav();92  const on = ids.has(r.uid);93  const label = !connected94    ? "Se connecter avec KA ID pour ajouter aux favoris"95    : on96      ? "Retirer de mes favoris (Mon univers Ka)"97      : "Ajouter à mes favoris (Mon univers Ka)";98  return (99    <button100      type="button"101      className={`fav-btn${on ? " on" : ""}${big ? " big" : ""}`}102      aria-label={label}103      aria-pressed={on}104      title={label}105      onClick={(e) => {106        e.preventDefault();       // la carte entière est un lien107        e.stopPropagation();108        toggle(restoFavItem(r));109      }}110    >111      {on ? "♥" : "♡"}112    </button>113  );114}115