Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-toggle": "^1.1.10",
"@radix-ui/react-toggle-group": "^1.1.11",
"@radix-ui/react-tooltip": "^1.2.8",
"@tailwindcss/vite": "^4.1.17",
"@tanstack/react-query": "^5.90.12",
"@tanstack/react-router": "^1.139.16",
Expand Down
36 changes: 36 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 10 additions & 7 deletions src/app/__root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { IconContext } from "react-icons"
import DevSettings from "@/components/DevSettings"
import Layout from "@/components/Layout"
import { Toaster } from "@/components/ui/sonner"
import { TooltipProvider } from "@/components/ui/tooltip"
import ContextProvider from "@/contexts/ContextProvider"

export const queryClient = new QueryClient()
Expand All @@ -19,14 +20,16 @@ function RootComponent() {
<IconContext.Provider
value={{ style: { verticalAlign: "middle", fontSize: "26px" } }}
>
<QueryClientProvider client={queryClient}>
<Layout>
<Outlet />
<TooltipProvider>
<QueryClientProvider client={queryClient}>
<Layout>
<Outlet />

{import.meta.env.DEV && <DevSettings />}
</Layout>
<Toaster richColors position="bottom-center" />
</QueryClientProvider>
{import.meta.env.DEV && <DevSettings />}
</Layout>
<Toaster richColors position="bottom-center" />
</QueryClientProvider>
</TooltipProvider>
</IconContext.Provider>
</ContextProvider>
</StrictMode>
Expand Down
2 changes: 1 addition & 1 deletion src/app/_home/$school/$year/$id/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ function RouteComponent() {
if (error)
return (
<Page>
<Alert level="error">Error: {error.message}</Alert>
<Alert level="error">{error.message}</Alert>
</Page>
)
return <Component ranking={ranking} />
Expand Down
77 changes: 21 additions & 56 deletions src/app/_home/$school/$year/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { useQuery } from "@tanstack/react-query"
import { createFileRoute, Link, redirect } from "@tanstack/react-router"
import { createFileRoute, redirect } from "@tanstack/react-router"
import Page from "@/components/custom-ui/Page"
import PhaseFlag from "@/components/custom-ui/PhaseFlag"
import { ButtonGrid } from "@/components/Homepage/ButtonGrid"
import { RankingSelector } from "@/components/Homepage/RankingSelector"
import PathBreadcrumb from "@/components/PathBreadcrumb"
import { Button } from "@/components/ui/button"
import { useQueries } from "@/hooks/use-queries"
import { getPhaseGroups, phaseGroupLabel, phaseLinkLabel } from "@/utils/phase"
import type { PhaseLink } from "@/utils/types/data/phase"
import { isSchool } from "@/utils/types/data/school"

Expand All @@ -24,63 +21,31 @@ function RouteComponent() {
const { school, year } = Route.useParams()
const queries = useQueries()
const { data, isPending } = useQuery(queries.index)

if (!data || isPending) return null
const yearData = data[school]?.[year] ?? []

const groups = getPhaseGroups(yearData).entriesArr()
const yearData = data[school]?.[year] ?? []
const phases: PhaseLink[] = yearData.map((entry) => ({
...entry.phase,
id: entry.id,
}))

return (
<Page>
<PathBreadcrumb />
<p className="w-full text-xl">Scegli una graduatoria</p>
{groups.map(([n, phases]) => (
<Group
key={`phasegroup-${n}`}
primary={n}
phases={phases}
showGeneral={groups.length > 1}
/>
))}
</Page>
)
}
<div className="w-full space-y-4">
<div className="space-y-1">
<h2 className="font-semibold text-slate-900 text-xl dark:text-slate-100">
Seleziona graduatoria
</h2>
<p className="text-slate-600 text-sm dark:text-slate-400">
Scegli la graduatoria da consultare per{" "}
<span className="font-medium">{school}</span> {year}
</p>
</div>

type GroupProps = {
primary: number
phases: PhaseLink[]
showGeneral: boolean
}

function Group({ primary, phases, showGeneral }: GroupProps) {
const { school, year } = Route.useParams()
return (
<>
{(showGeneral || primary !== 0) && <p>{phaseGroupLabel(primary)}</p>}
<ButtonGrid length={phases.length}>
{phases.map((phase) => (
<Link
to="/$school/$year/$id"
params={{ school, year, id: phase.id }}
key={phase.id}
className="h-full"
>
<Button
size="card"
variant="secondary"
className="relative h-full w-full"
>
<span className="whitespace text-base">
{phaseLinkLabel(phase)}
</span>
<div className="absolute right-0 bottom-0 flex overflow-hidden rounded-tl-lg">
<div className="bg-slate-700 px-3 py-1">
<PhaseFlag phase={phase} />
</div>
</div>
</Button>
</Link>
))}
</ButtonGrid>
</>
<RankingSelector phases={phases} school={school} year={year} />
</div>
</Page>
)
}
69 changes: 45 additions & 24 deletions src/app/_home/$school/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { useQuery } from "@tanstack/react-query"
import { createFileRoute, Link, redirect } from "@tanstack/react-router"
import { useState } from "react"
import Page from "@/components/custom-ui/Page"
import Spinner from "@/components/custom-ui/Spinner"
import { ButtonGrid } from "@/components/Homepage/ButtonGrid"
import PathBreadcrumb from "@/components/PathBreadcrumb"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { useQueries } from "@/hooks/use-queries"
import { isSchool } from "@/utils/types/data/school"
import { cn } from "@/utils/ui"

export const Route = createFileRoute("/_home/$school/")({
component: RouteComponent,
Expand All @@ -20,39 +18,62 @@ export const Route = createFileRoute("/_home/$school/")({
})

function RouteComponent() {
const [clicked, setClicked] = useState(false)
const { school } = Route.useParams()
const queries = useQueries()
const { data, isPending } = useQuery(queries.index)

if (!data || isPending) return null
const years = Object.keys(data[school] ?? {}).map(Number)
const years = Object.keys(data[school] ?? {})
.map(Number)
.sort((a, b) => b - a)

return clicked ? (
<div className="w-full">
<Spinner />
</div>
) : (
return (
<Page>
<PathBreadcrumb />
<p className="w-full text-xl">Scegli un anno di immatricolazione</p>
<ButtonGrid length={years.length}>
{years
.sort((a, b) => b - a)
.map((year) => (
<div className="space-y-1">
<h2 className="font-semibold text-slate-900 text-xl dark:text-slate-100">
Anno di immatricolazione
</h2>
<p className="text-slate-600 text-sm dark:text-slate-400">
Seleziona l'anno accademico di cui vuoi consultare le graduatorie
</p>
</div>

<div className="flex w-full grid-cols-2 flex-wrap gap-3 max-sm:grid">
{years.map((year, index) => {
const isFirst = index === 0

return (
<Link
key={year}
to="/$school/$year"
params={{ school, year }}
key={year}
className="h-full"
onClick={() => setClicked(true)}
className="group"
>
<Button size="card" variant="secondary" className="h-full w-full">
<span className="text-lg">{year}</span>
</Button>
<Badge
size="large"
variant="secondary"
className={cn(
"w-full cursor-pointer justify-center border transition-all hover:bg-slate-200 hover:no-underline dark:hover:bg-slate-700/80",
isFirst
? "border-amber-700/30 shadow-[0px_2px_10px_#ffae1082,inset_0px_-4px_20px_#ffb52575] dark:border-amber-200/90 dark:shadow-[0px_3px_8px_rgba(186,130,21,0.32),inset_0px_-4px_20px_rgba(186,130,21,0.43)]"
: ""
)}
>
{year}
</Badge>
</Link>
))}
</ButtonGrid>
)
})}
</div>

{years.length > 0 && (
<p className="text-slate-500 text-xs dark:text-slate-500">
{years.length}{" "}
{years.length === 1 ? "anno disponibile" : "anni disponibili"} dal{" "}
{years[years.length - 1]} al {years[0]}
</p>
)}
</Page>
)
}
61 changes: 28 additions & 33 deletions src/app/_home/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { useQuery } from "@tanstack/react-query"
import { createFileRoute, Link } from "@tanstack/react-router"
import { createFileRoute } from "@tanstack/react-router"
import Alert from "@/components/custom-ui/Alert"
import Page from "@/components/custom-ui/Page"
import Spinner from "@/components/custom-ui/Spinner"
import { ButtonGrid } from "@/components/Homepage/ButtonGrid"
import { SchoolEmoji } from "@/components/school-emoji"
import { Button } from "@/components/ui/button"
import { ArchiveTip } from "@/components/Homepage/ArchiveTip"
import { SchoolCard } from "@/components/Homepage/SchoolCard"
import { useQueries } from "@/hooks/use-queries"

export const Route = createFileRoute("/_home/")({
Expand All @@ -22,40 +21,36 @@ function RouteComponent() {

return (
<Page>
<div className="flex w-full flex-1 flex-col items-start gap-4 py-4">
<h3 className="w-full font-bold text-2xl">
👋 Ciao!{" "}
<span className="whitespace-nowrap">Questo sito raccoglie</span>{" "}
<span className="whitespace-nowrap">lo storico</span>{" "}
<span className="whitespace-nowrap">delle graduatorie</span>{" "}
<span className="whitespace-nowrap">del Politecnico di Milano.</span>
</h3>
<p className="w-full text-xl">
Inizia scegliendo l'area di studi di tuo interesse
</p>
<div className="flex w-full flex-1 flex-col items-start gap-6 py-4">
<div className="space-y-2">
<h1 className="font-bold text-2xl text-slate-900 tracking-tight sm:text-3xl dark:text-slate-100">
Storico Graduatorie PoliMi
</h1>
<p className="text-slate-600 dark:text-slate-400">
Consulta le graduatorie storiche del Politecnico di Milano.
Seleziona un'area di studi per iniziare.
</p>
</div>

{schools && (
<ButtonGrid length={schools.length}>
<div className="grid w-full grid-cols-1 gap-4 sm:grid-cols-2">
{schools.map((school) => (
<Link
to="/$school"
params={{ school }}
key={school}
className="h-full"
>
<Button
size="card"
variant="secondary"
className="h-full w-full"
>
<SchoolEmoji school={school} />
<span className="text-lg">{school}</span>
</Button>
</Link>
<SchoolCard key={school} school={school} />
))}
</ButtonGrid>
</div>
)}

{isPending && (
<div className="flex w-full justify-center py-12">
<Spinner />
</div>
)}
{isPending && <Spinner />}
{error instanceof Error && <Alert level="error">{error.message}</Alert>}

<div className="flex-1"></div>
<div className="flex w-full justify-center">
{data && <ArchiveTip data={data} />}
</div>
</div>
</Page>
)
Expand Down
Loading
Loading