You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
website/src/client/UtentiPage.tsx

156 lines
4.8 KiB
TypeScript

import { useComputed, useSignal } from '@preact/signals'
import Fuse from 'fuse.js'
import { useEffect } from 'preact/hooks'
import { ShowMore } from './Paginate'
import { ComboBox } from './ComboBox'
type User = {
uid: string
gecos: string
}
const FILTERS = {
utenti: {
icon: 'person',
label: 'Utenti',
},
macchinisti: {
icon: 'construction',
label: 'Macchinisti',
},
rappstud: {
icon: 'account_balance',
label: 'Rappresentanti',
},
}
function applyPatches(users: User[]) {
users.forEach(user => {
// strip ",+" from the end of the gecos field
user.gecos = user.gecos.replace(/,+$/, '')
// capitalize the first letter of each word
user.gecos = user.gecos.replace(/\b\w/g, c => c.toUpperCase())
})
// reverse the order of the users
users.reverse()
}
const MACCHINISTI = ['delucreziis', 'minnocci', 'baldino', 'manicastri', 'llombardo', 'serdyuk']
const RAPPSTUD = [
'smannella',
'lotti',
'rotolo',
'saccani',
'carbone',
'mburatti',
'ppuddu',
'marinari',
'evsilvestri',
'tateo',
'graccione',
'dilella',
'rocca',
'odetti',
'borso',
'numero',
]
export const UtentiPage = () => {
const $utentiData = useSignal<User[]>([])
const $filter = useSignal('utenti')
const $filteredData = useComputed(() =>
$filter.value === 'macchinisti'
? $utentiData.value.filter(user => MACCHINISTI.includes(user.uid))
: $filter.value === 'rappstud'
? $utentiData.value.filter(user => RAPPSTUD.includes(user.uid))
: $utentiData.value
)
const $fuse = useComputed(
() =>
new Fuse($filteredData.value, {
keys: ['gecos', 'uid'],
})
)
const $searchText = useSignal('')
const $searchResults = useComputed(() =>
$searchText.value.trim().length > 0
? $fuse.value?.search($searchText.value).map(result => result.item) ?? []
: $filteredData.value
)
useEffect(() => {
fetch('https://poisson.phc.dm.unipi.it/users.json')
.then(response => response.json())
.then(data => {
applyPatches(data)
$utentiData.value = data
$fuse.value.setCollection(data)
})
}, [])
return (
<>
<div class="search-bar">
<ComboBox value={$filter.value} setValue={s => ($filter.value = s)}>
{Object.fromEntries(
Object.entries(FILTERS).map(([k, v]) => [
k,
<>
<span class="material-symbols-outlined">{v.icon}</span> {v.label}
</>,
])
)}
</ComboBox>
<div class="search">
<input
type="text"
placeholder="Cerca un utente Poisson..."
onInput={e => ($searchText.value = e.currentTarget.value)}
value={$searchText.value}
/>
<span class="material-symbols-outlined">search</span>
</div>
</div>
<div class="search-results">
{$searchResults.value ? (
<ShowMore items={$searchResults} pageSize={100}>
{poissonUser => (
<div class="search-result">
<div class="icon">
<span class="material-symbols-outlined">
{RAPPSTUD.includes(poissonUser.uid)
? 'account_balance'
: MACCHINISTI.includes(poissonUser.uid)
? 'construction'
: 'person'}
</span>
</div>
<div class="text">{poissonUser.gecos}</div>
<div class="right">
<a
href={`https://poisson.phc.dm.unipi.it/~${poissonUser.uid}`}
target="_blank"
>
<span class="material-symbols-outlined">open_in_new</span>
</a>
</div>
</div>
)}
</ShowMore>
) : (
<>Nessun risultato</>
)}
</div>
</>
)
}