diff --git a/apps/infoalloggi/src/components/servizio/servizio.tsx b/apps/infoalloggi/src/components/servizio/servizio.tsx
index 1abfac2..ac9a3ef 100644
--- a/apps/infoalloggi/src/components/servizio/servizio.tsx
+++ b/apps/infoalloggi/src/components/servizio/servizio.tsx
@@ -287,6 +287,7 @@ const Main = () => {
+ {isAdmin && }
);
}
@@ -378,6 +379,7 @@ const Main = () => {
+ {isAdmin && }
);
}
diff --git a/apps/infoalloggi/src/components/tables/richieste-table.tsx b/apps/infoalloggi/src/components/tables/richieste-table.tsx
new file mode 100644
index 0000000..6ad3afc
--- /dev/null
+++ b/apps/infoalloggi/src/components/tables/richieste-table.tsx
@@ -0,0 +1,200 @@
+import type { ColumnDef } from "@tanstack/react-table";
+import { ExternalLink } from "lucide-react";
+import Link from "next/link";
+import { DataTable } from "~/components/custom_ui/data-table";
+import { DataTableColumnHeader } from "~/components/custom_ui/dataTable-header";
+import type {
+ PinnedFiltro,
+ SearchFiltro,
+} from "~/components/custom_ui/dataTable-toolbar";
+import { Button } from "~/components/ui/button";
+import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum";
+import type { RichiesteData } from "~/server/controllers/servizio.controller";
+
+type RichiesteTableProps = {
+ data: RichiesteData[];
+};
+
+export const RichiesteTable = ({ data }: RichiesteTableProps) => {
+ const tabledata = data;
+
+ const columns_titles = {
+ id: "ID Ordine",
+ username: "Utente",
+ created_at: "Creato il",
+ status: "Status",
+ tipo: "Tipo",
+ annunci: "Annunci",
+ actions: "Azioni",
+ };
+ const statusOptions = [
+ { label: "Attesa di attivazione", value: "attesa_attivazione" },
+ { label: "Acconto pagato", value: "acconto_pagato" },
+ { label: "Saldo pagato", value: "saldo_pagato" },
+ { label: "Conferma in corso", value: "conferma" },
+ ];
+
+ const type_options = [
+ { label: "Transitorio", value: TipologiaPosizioneEnum.Transitorio },
+ { label: "Stabile", value: TipologiaPosizioneEnum.Stabile },
+ ];
+
+ // const [selectedOrdine, setSelectedOrdine] = useState(
+ // null,
+ // );
+
+ type Column = (typeof tabledata)[number];
+
+ const columns: ColumnDef[] = [
+ {
+ accessorKey: "id",
+ cell: () => null,
+ enableHiding: false,
+ header: () => null,
+ },
+
+ {
+ accessorKey: "username",
+ cell: ({ row }) => {
+ return (
+
+
+
+ );
+ },
+ enableHiding: false,
+ header: ({ column }) => (
+
+ ),
+ },
+ {
+ accessorKey: "created_at",
+ cell: ({ row }) => {
+ const date = row.getValue("created_at");
+ return new Date(date as Date).toLocaleDateString();
+ },
+ enableHiding: false,
+ header: ({ column }) => (
+
+ ),
+ sortingFn: "datetime",
+ },
+ {
+ accessorKey: "tipologia",
+ cell: ({ row }) => {
+ return row.original.tipologia.toString();
+ },
+ filterFn: (row, id, value) => {
+ return value.includes(row.getValue(id));
+ },
+ header: ({ column }) => (
+
+ ),
+ },
+
+ {
+ accessorKey: "status",
+ cell: ({ row }) => {
+ const annunci = row.original.annunci_servizio;
+
+ const awaitingConferma = annunci.some(
+ (a) => a.user_confirmed_at !== null && !a.hasConfermaAdmin,
+ );
+ if (awaitingConferma) {
+ return "Conferma in corso";
+ }
+
+ if (row.original.isOkSaldo) {
+ return "Saldo pagato";
+ }
+ if (row.original.isOkAcconto) {
+ return "Acconto pagato";
+ }
+ if (!row.original.onboardOk) {
+ return "Attesa di attivazione";
+ }
+ },
+
+ filterFn: (row, id, value) => {
+ return value.includes(row.getValue(id));
+ },
+ header: ({ column }) => (
+
+ ),
+ },
+ {
+ accessorKey: "annunci_servizio",
+ cell: ({ row }) => {
+ const annunci = row.original.annunci_servizio;
+ return {annunci.length};
+ },
+ header: ({ column }) => (
+
+ ),
+ enableSorting: false,
+ },
+ {
+ cell: () => {
+ return (
+
+ );
+ },
+ enableHiding: false,
+ id: "actions",
+ },
+ ];
+
+ const searchFiltro: SearchFiltro = {
+ columnName: "id",
+ placeholder: "Cerca ordine...",
+ };
+
+ const pinnedFiltri: PinnedFiltro[] = [
+ {
+ columnName: "status",
+
+ options: statusOptions,
+ title: "Stato Ordine",
+ },
+ {
+ columnName: "tipo",
+ options: type_options,
+ title: "Tipo Ordine",
+ },
+ ];
+
+ return (
+
+ );
+};
diff --git a/apps/infoalloggi/src/pages/area-riservata/admin/richieste.tsx b/apps/infoalloggi/src/pages/area-riservata/admin/richieste.tsx
new file mode 100644
index 0000000..e980394
--- /dev/null
+++ b/apps/infoalloggi/src/pages/area-riservata/admin/richieste.tsx
@@ -0,0 +1,58 @@
+import type { GetServerSideProps } from "next";
+import Head from "next/head";
+import { AreaRiservataLayout } from "~/components/Layout";
+import { LoadingPage } from "~/components/loading";
+import { Status500 } from "~/components/status-page";
+import { RichiesteTable } from "~/components/tables/richieste-table";
+import type { NextPageWithLayout } from "~/pages/_app";
+import { TrpcAuthedFetchingIstance } from "~/server/utils/ssgHelper";
+import { api } from "~/utils/api";
+
+/**
+ * Pagina di gestione richieste per admin: /area-riservata/admin/richieste
+ */
+const Richieste: NextPageWithLayout = () => {
+ const { data, isLoading } = api.servizio.getRichieste.useQuery();
+
+ if (isLoading) return ;
+ if (!data) return ;
+
+ return (
+ <>
+
+ Richieste - Infoalloggi.it
+
+
+
+ >
+ );
+};
+export default Richieste;
+
+export const getServerSideProps = (async (context) => {
+ const access_token = context.req.cookies.access_token;
+
+ const helpers = await TrpcAuthedFetchingIstance({ access_token });
+ if (helpers) {
+ await helpers.trpc.servizio.getRichieste.prefetch();
+ return {
+ props: {
+ trpcState: helpers.trpc.dehydrate(),
+ },
+ };
+ }
+ return {
+ props: {},
+ };
+}) satisfies GetServerSideProps;
+
+Richieste.getLayout = function getLayout(page) {
+ return {page};
+};
diff --git a/apps/infoalloggi/src/server/api/routers/servizio.ts b/apps/infoalloggi/src/server/api/routers/servizio.ts
index d510b51..28b91dc 100644
--- a/apps/infoalloggi/src/server/api/routers/servizio.ts
+++ b/apps/infoalloggi/src/server/api/routers/servizio.ts
@@ -20,6 +20,7 @@ import {
getCompatibileAnnunci,
getDataPerAcquisto,
getOrdineRicevutaData,
+ getRichieste,
getServiziByUserId,
getServizioDataById,
InteractionLogicTipologia,
@@ -119,6 +120,9 @@ export const servizioRouter = createTRPCRouter({
.query(async ({ input }) => {
return await getAllServizioAnnunci(input.userId);
}),
+ getRichieste: adminProcedure.query(async () => {
+ return await getRichieste();
+ }),
getServizioData: protectedProcedure
.input(
z.object({
diff --git a/apps/infoalloggi/src/server/controllers/servizio.controller.ts b/apps/infoalloggi/src/server/controllers/servizio.controller.ts
index 73c2e56..77e573e 100644
--- a/apps/infoalloggi/src/server/controllers/servizio.controller.ts
+++ b/apps/infoalloggi/src/server/controllers/servizio.controller.ts
@@ -1,3 +1,4 @@
+import type { Override } from "TypeHelpers.type";
import { TRPCError } from "@trpc/server";
import { add } from "date-fns";
import { jsonArrayFrom, jsonObjectFrom } from "kysely/helpers/postgres";
@@ -1399,3 +1400,67 @@ export const getOrdineRicevutaData = async ({
});
}
};
+export type RichiesteData = Servizio &
+ Pick & {
+ annunci_servizio: (Override<
+ ServizioAnnunci,
+ {
+ created_at: string;
+ open_contatti_at: string | null;
+ user_confirmed_at: string | null;
+ accettato_conferma_at: string | null;
+ contratto_decorrenza: string | null;
+ contratto_scadenza: string | null;
+ }
+ > &
+ Pick)[];
+ ordini_servizio: (Override<
+ Ordini,
+ {
+ created_at: string;
+ paid_at: string | null;
+ }
+ > &
+ Pick)[];
+ };
+
+export const getRichieste = async (): Promise => {
+ try {
+ return await db
+ .selectFrom("servizio")
+ .innerJoin("users", "users.id", "servizio.user_id")
+ .selectAll("servizio")
+ .select(["users.username"])
+ .select((eb) => [
+ jsonArrayFrom(
+ eb
+ .selectFrom("servizio_annunci")
+ .selectAll("servizio_annunci")
+ .innerJoin("annunci", "annunci.id", "servizio_annunci.annunci_id")
+ .select(["annunci.codice", "annunci.titolo_it"])
+ .whereRef(
+ "servizio.servizio_id",
+ "=",
+ "servizio_annunci.servizio_id",
+ )
+ .orderBy("servizio_annunci.created_at", "desc"),
+ ).as("annunci_servizio"),
+ jsonArrayFrom(
+ eb
+ .selectFrom("ordini")
+ .selectAll("ordini")
+ .innerJoin("prezziario", "prezziario.idprezziario", "ordini.packid")
+ .select("prezziario.testo_condizioni")
+ .whereRef("ordini.servizio_id", "=", "servizio.servizio_id")
+ .orderBy("ordini.created_at", "desc"),
+ ).as("ordini_servizio"),
+ ])
+ .orderBy("servizio.created_at", "desc")
+ .execute();
+ } catch (e) {
+ throw new TRPCError({
+ code: "INTERNAL_SERVER_ERROR",
+ message: `Error fetching richieste: ${(e as Error).message}`,
+ });
+ }
+};