/* global React, Card, Button, Input, Ic, VS, LoadingState, ErrorState */ function MyStampScreen() { const [stamp, setStamp] = React.useState(null); const [err, setErr] = React.useState(''); const [msg, setMsg] = React.useState(''); const [busy, setBusy] = React.useState(false); const [imgBust, setImgBust] = React.useState(0); const fileInputRef = React.useRef(null); const role = VS.getRole(); const isAdmin = role === 'admin'; // admin: wszystkie pieczątki const [allStamps, setAllStamps] = React.useState(null); const [allStampsErr, setAllStampsErr] = React.useState(''); const [allBust, setAllBust] = React.useState({}); React.useEffect(() => { VS.myStamp() .then((s) => setStamp(s)) .catch((e) => setErr(e.message)); }, []); React.useEffect(() => { if (!isAdmin) return; VS.userStamps() .then((list) => setAllStamps(list)) .catch((e) => setAllStampsErr(e.message)); }, [isAdmin]); function setField(k, v) { setStamp((s) => ({ ...s, [k]: v })); } async function save() { if (!stamp) return; setBusy(true); setMsg(''); try { await VS.saveMyStamp({ name: stamp.name || '', cert_number: stamp.cert_number || '' }); setMsg('Zapisano.'); setTimeout(() => setMsg(''), 2500); } catch (e) { setMsg('Błąd: ' + e.message); } finally { setBusy(false); } } async function uploadImage(e) { const file = e.target.files && e.target.files[0]; if (!file) return; setBusy(true); setMsg(''); try { await VS.uploadMyStampImage(file); setStamp((s) => ({ ...s, has_image: true })); setImgBust((x) => x + 1); setMsg('Obrazek wgrany.'); setTimeout(() => setMsg(''), 2500); } catch (err) { setMsg('Błąd: ' + err.message); } finally { setBusy(false); e.target.value = ''; } } if (err) return ; if (!stamp) return ; return (
Pieczątka

Moja pieczątka

Dane pieczątki wykorzystywane w protokołach i raportach.
Moja pieczątka
{msg && ( {msg} )}
setField('name', v)} /> setField('cert_number', v)} />
Obrazek pieczątki
{stamp.has_image ? ( pieczątka ) : ( brak )}
PNG lub JPEG, rekomendowane 400×160 px.
{isAdmin && ( )}
); } function StampField({ label, value, onChange }) { return ( ); } function AdminStampsSection({ stamps, setStamps, err, allBust, setAllBust }) { const [open, setOpen] = React.useState(true); return (
setOpen((o) => !o)} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', cursor: 'pointer', userSelect: 'none', }} >
Administracja
Pieczątki wszystkich użytkowników
{open && (
{err && (
{err}
)} {!stamps && !err &&
Ładowanie…
} {stamps && stamps.length === 0 && (
Brak użytkowników.
)} {stamps && stamps.length > 0 && (
Użytkownik
Imię i nazwisko
Nr świadectwa
Pieczątka
Akcje
{stamps.map((row) => ( { setStamps((list) => list.map((s) => (s.user_id === row.user_id ? { ...s, ...patch } : s))); }} bumpBust={() => setAllBust((b) => ({ ...b, [row.user_id]: (b[row.user_id] || 0) + 1 })) } /> ))}
)}
)}
); } function AdminStampRow({ row, onChange, bust, bumpBust }) { const [busy, setBusy] = React.useState(false); const [msg, setMsg] = React.useState(''); const fileRef = React.useRef(null); async function save() { setBusy(true); setMsg(''); try { await VS.saveUserStamp(row.user_id, { name: row.name || '', cert_number: row.cert_number || '' }); setMsg('OK'); setTimeout(() => setMsg(''), 2000); } catch (e) { setMsg('Błąd'); } finally { setBusy(false); } } async function upload(e) { const file = e.target.files && e.target.files[0]; if (!file) return; setBusy(true); setMsg(''); try { await VS.uploadUserStampImage(row.user_id, file); onChange({ has_image: true }); bumpBust(); setMsg('OK'); setTimeout(() => setMsg(''), 2000); } catch (err) { setMsg('Błąd'); } finally { setBusy(false); e.target.value = ''; } } return (
{row.username}
{row.role || 'user'}
onChange({ name: e.target.value })} placeholder="Imię i nazwisko" style={{ width: '100%', height: 28, padding: '0 10px', background: 'var(--surface)', border: '1px solid var(--border-strong)', borderRadius: 'var(--r-sm)', fontSize: 12, color: 'var(--fg)', outline: 'none', fontFamily: 'inherit', }} /> onChange({ cert_number: e.target.value })} placeholder="nr świadectwa" style={{ width: '100%', height: 28, padding: '0 10px', background: 'var(--surface)', border: '1px solid var(--border-strong)', borderRadius: 'var(--r-sm)', fontSize: 12, color: 'var(--fg)', outline: 'none', fontFamily: 'inherit', }} />
{row.has_image ? ( ) : ( brak )}
{msg && ( {msg} )}
); } Object.assign(window, { MyStampScreen });