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.
156 lines
4.8 KiB
TypeScript
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>
|
|
</>
|
|
)
|
|
}
|