spb/company-atlas
Public
Python 66.3%
TypeScript 22.7%
JavaScript 8.6%
HTML 1.4%
CSS 0.7%
1'use client';2import { Bookmark, BookmarkCheck } from 'lucide-react';3import { useState } from 'react';4import { ownerApi } from '@/lib/client-api';5import { cn } from '@/lib/cn';6import { ensureOwnerToken, readWatched, useWatched, writeWatched } from '@/lib/owner';78/** Watch / unwatch a company (owner token generated on first use). Optimistic; mirrors the slug locally. */9export function WatchButton({ slug, name, className, size = 'md' }: { slug: string; name?: string; className?: string; size?: 'sm' | 'md' }) {10 const watched = useWatched();11 const on = watched.includes(slug);12 const [busy, setBusy] = useState(false);13 const [err, setErr] = useState<string | null>(null);14 const toggle = async () => {15 setBusy(true);16 setErr(null);17 const token = ensureOwnerToken();18 const api = ownerApi(token);19 const cur = readWatched();20 try {21 if (on) {22 writeWatched(cur.filter((s) => s !== slug));23 await api.unwatch(slug);24 } else {25 writeWatched([...cur, slug]);26 await api.watch(slug);27 }28 } catch (e) {29 writeWatched(cur);30 setErr((e as Error).message || 'Could not update watchlist');31 } finally {32 setBusy(false);33 }34 };35 return (36 <span className={cn('inline-flex flex-col items-start', className)}>37 <button type="button" onClick={toggle} disabled={busy} aria-pressed={on} className={cn('btn', size === 'sm' && 'btn-sm', on && 'border-accent bg-accent-soft text-accent')} data-watch={slug} title={on ? `Stop watching ${name ?? slug}` : `Watch ${name ?? slug}`}>38 {on ? <BookmarkCheck className="size-4" aria-hidden /> : <Bookmark className="size-4" aria-hidden />}39 {on ? 'Watching' : 'Watch'}40 </button>41 {err && <span className="mt-1 text-[11px] text-danger">{err}</span>}42 </span>43 );44}45