Compare commits

..

9 commits

71 changed files with 14386 additions and 1162 deletions

7
.dockerignore Normal file
View file

@ -0,0 +1,7 @@
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
.git

2
.gitignore vendored
View file

@ -39,3 +39,5 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
/prisma/generated/prisma

4
.prettierrc Normal file
View file

@ -0,0 +1,4 @@
{
"tabWidth": 2,
"useTabs": false
}

View file

@ -1,38 +1,44 @@
# Fase 1: Build
FROM node:18-alpine AS builder
FROM node:22-alpine AS base
RUN apk add --no-cache libc6-compat openssl
# Imposta la directory di lavoro
WORKDIR /app
# Copia i file di configurazione e dipendenze
COPY package.json pnpm-lock.yaml* ./
# --- STAGE 1 ---
FROM base AS deps
COPY package.json ./
RUN npm install
# Installa le dipendenze
RUN npm install --force
# Copia il resto dei file dell'app
# --- STAGE 2 ---
FROM base AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Build dell'app Next.js
RUN npx prisma generate
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
# Fase 2: Runtime (immagine più leggera)
FROM node:18-alpine AS runner
# Imposta la directory di lavoro
# --- STAGE 3 ---
FROM base AS runner
WORKDIR /app
# Imposta variabile d'ambiente per produzione
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copia solo ciò che serve per l'esecuzione
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
# Porta esposta (3000 di default per Next.js)
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
# Comando di avvio
CMD ["npm", "start"]
CMD ["node", "server.js"]

View file

@ -1,11 +1,27 @@
services:
app:
container_name: dashregistratori
build:
context: .
webapp:
build: .
container_name: dash-registratori
restart: unless-stopped
ports:
- 3001:3000
dns: 1.1.1.1
- "3000:3000"
environment:
NODE_ENV: development
DATABASE_URL: "postgresql://postgres:postgres@db:5432/db?schema=public"
depends_on:
- db
db:
image: postgres:alpine
container_name: db
restart: unless-stopped
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: db
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:

View file

@ -2,6 +2,14 @@ import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "standalone",
typescript: {
ignoreBuildErrors: true,
},
eslint: {
ignoreDuringBuilds: true,
},
};
export default nextConfig;

1239
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -8,23 +8,29 @@
"start": "next start"
},
"dependencies": {
"@prisma/client": "^6.18.0",
"@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.12",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-slot": "^1.2.4",
"@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tooltip": "^1.2.8",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"date-fns": "^4.1.0",
"leaflet": "^1.9.4",
"leaflet-defaulticon-compatibility": "^0.1.2",
"lucide-react": "^0.546.0",
"next": "15.5.5",
"prisma": "^6.17.1",
"react": "19.1.0",
"react-day-picker": "^9.11.1",
"react-dom": "19.1.0",
"react-leaflet": "^5.0.0",
"tailwind-merge": "^3.3.1"
@ -35,6 +41,7 @@
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"prisma": "^6.18.0",
"tailwindcss": "^4",
"tw-animate-css": "^1.4.0",
"typescript": "^5"

View file

@ -0,0 +1,41 @@
-- CreateTable
CREATE TABLE "Intervento" (
"id" SERIAL NOT NULL,
"id_registratore" INTEGER NOT NULL,
"data" DATE NOT NULL,
"lavoro" TEXT NOT NULL,
"fattura" BOOLEAN NOT NULL,
CONSTRAINT "Intervento_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Registratore" (
"id" SERIAL NOT NULL,
"id_cliente" INTEGER NOT NULL,
CONSTRAINT "Registratore_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Cliente" (
"id" SERIAL NOT NULL,
"ragione_sociale" VARCHAR(255) NOT NULL,
"email" VARCHAR(255) NOT NULL,
"partita_iva" VARCHAR(255) NOT NULL,
"telefono" VARCHAR(255) NOT NULL,
"sede" VARCHAR(255) NOT NULL,
"sede_url" VARCHAR(255) NOT NULL,
"contratto" VARCHAR(255) NOT NULL,
CONSTRAINT "Cliente_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "Cliente_ragione_sociale_key" ON "Cliente"("ragione_sociale");
-- AddForeignKey
ALTER TABLE "Intervento" ADD CONSTRAINT "Intervento_id_registratore_fkey" FOREIGN KEY ("id_registratore") REFERENCES "Registratore"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Registratore" ADD CONSTRAINT "Registratore_id_cliente_fkey" FOREIGN KEY ("id_cliente") REFERENCES "Cliente"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View file

@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "Registratore" ADD COLUMN "data_acquisto" DATE,
ADD COLUMN "prossima_verifica" DATE,
ADD COLUMN "seriale" VARCHAR(255),
ADD COLUMN "ultima_verifica" DATE;

View file

@ -0,0 +1,21 @@
/*
Warnings:
- The primary key for the `Registratore` table will be changed. If it partially fails, the table could be left without primary key constraint.
*/
-- DropForeignKey
ALTER TABLE "public"."Intervento" DROP CONSTRAINT "Intervento_id_registratore_fkey";
-- AlterTable
ALTER TABLE "Intervento" ALTER COLUMN "id_registratore" SET DATA TYPE TEXT;
-- AlterTable
ALTER TABLE "Registratore" DROP CONSTRAINT "Registratore_pkey",
ALTER COLUMN "id" DROP DEFAULT,
ALTER COLUMN "id" SET DATA TYPE TEXT,
ADD CONSTRAINT "Registratore_pkey" PRIMARY KEY ("id");
DROP SEQUENCE "Registratore_id_seq";
-- AddForeignKey
ALTER TABLE "Intervento" ADD CONSTRAINT "Intervento_id_registratore_fkey" FOREIGN KEY ("id_registratore") REFERENCES "Registratore"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View file

@ -0,0 +1,8 @@
/*
Warnings:
- You are about to drop the column `seriale` on the `Registratore` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE "Registratore" DROP COLUMN "seriale";

View file

@ -0,0 +1,5 @@
-- CreateEnum
CREATE TYPE "Modello" AS ENUM ('FORM100', 'FORM200', 'FORM500');
-- AlterTable
ALTER TABLE "Registratore" ADD COLUMN "modello" "Modello";

View file

@ -0,0 +1,2 @@
-- AlterEnum
ALTER TYPE "Modello" ADD VALUE 'FORM200PLUS';

View file

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Cliente" ADD COLUMN "coordinate" DOUBLE PRECISION[];

View file

@ -0,0 +1,10 @@
/*
Warnings:
- You are about to drop the column `coordinate` on the `Cliente` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE "Cliente" DROP COLUMN "coordinate",
ADD COLUMN "lat" DOUBLE PRECISION,
ADD COLUMN "lon" DOUBLE PRECISION;

View file

@ -0,0 +1,10 @@
/*
Warnings:
- Made the column `lat` on table `Cliente` required. This step will fail if there are existing NULL values in that column.
- Made the column `lon` on table `Cliente` required. This step will fail if there are existing NULL values in that column.
*/
-- AlterTable
ALTER TABLE "Cliente" ALTER COLUMN "lat" SET NOT NULL,
ALTER COLUMN "lon" SET NOT NULL;

View file

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Cliente" ALTER COLUMN "sede_url" SET DATA TYPE TEXT;

View file

@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"

50
prisma/schema.prisma Normal file
View file

@ -0,0 +1,50 @@
generator client {
provider = "prisma-client-js"
output = "../src/generated/prisma"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum Modello {
FORM100
FORM200
FORM200PLUS
FORM500
}
model Intervento {
id Int @id @default(autoincrement())
id_registratore String
data DateTime @db.Date
lavoro String @db.Text
fattura Boolean @db.Boolean
registratore Registratore @relation(fields: [id_registratore], references: [id])
}
model Registratore {
id String @id
id_cliente Int
modello Modello?
data_acquisto DateTime? @db.Date
ultima_verifica DateTime? @db.Date
prossima_verifica DateTime? @db.Date
cliente Cliente @relation(fields: [id_cliente], references: [id])
interventi Intervento[]
}
model Cliente {
id Int @id @default(autoincrement())
ragione_sociale String @unique @db.VarChar(255)
email String @db.VarChar(255)
partita_iva String @db.VarChar(255)
telefono String @db.VarChar(255)
sede String @db.VarChar(255)
sede_url String
contratto String @db.VarChar(255)
lat Float
lon Float
registratori Registratore[]
}

View file

@ -0,0 +1,24 @@
import { PrismaClient } from "@/generated/prisma";
export async function GET(
request: Request,
{ params }: { params: Promise<{ id: string }> },
) {
const prisma = new PrismaClient();
const { id } = await params;
const cliente = await prisma.cliente.findUnique({
where: {
id: Number(id),
},
include: {
registratori: {
include: {
interventi: true,
},
},
},
});
return Response.json({ cliente });
}

View file

@ -0,0 +1,66 @@
import { Modello, PrismaClient } from "@/generated/prisma";
export async function GET(request: Request) {
const prisma = new PrismaClient();
const clients = await prisma.cliente.findMany({
include: {
registratori: {
include: {
interventi: true,
},
},
},
});
return Response.json({ clients });
}
function extractLatLonFromGmapsUrl(url: string) {
// Usa una regex per cercare la latitudine e la longitudine nell'URL
const regex = /@(-?\d+\.\d+),(-?\d+\.\d+)/;
const match = url.match(regex);
if (match) {
const lat = parseFloat(match[1]);
const lon = parseFloat(match[2]);
return [lat, lon]; // Restituisce un array con latitudine e longitudine
} else {
return [0, 0]; // Se non trova latitudine e longitudine
}
}
export async function POST(request: Request) {
const prisma = new PrismaClient();
const data = await request.json();
const [lat, lon] = extractLatLonFromGmapsUrl(data.sede_url);
await prisma.cliente.create({
data: {
contratto: data.contratto,
email: data.email,
partita_iva: data.partita_iva,
ragione_sociale: data.ragione_sociale,
sede: data.sede,
sede_url: data.sede_url,
telefono: data.telefono,
lat: lat,
lon: lon,
/*registratori: {
create: {
id: "80E1758414",
modello: Modello.FORM100,
interventi: {
create: {
data: new Date("2025-10-30"),
fattura: true,
lavoro: "Boh, cazzeggiato tutto il tempo",
},
},
},
},*/
},
});
return Response.json({ message: "fatto bastardo" });
}

View file

@ -0,0 +1,17 @@
import { PrismaClient } from "@/generated/prisma";
export async function POST(request: Request) {
const prisma = new PrismaClient();
const data = await request.json();
await prisma.intervento.create({
data: {
id_registratore: data.id,
data: new Date(data.data),
lavoro: data.lavoro,
fattura: data.fattura,
},
});
return Response.json({ message: "fatto bastardo" });
}

View file

@ -0,0 +1,17 @@
import { PrismaClient } from "@/generated/prisma";
export async function GET(
request: Request,
{ params }: { params: Promise<{ id: string }> },
) {
const prisma = new PrismaClient();
const { id }: { id: string } = await params;
const cliente = await prisma.intervento.findMany({
where: {
id_registratore: id,
},
});
return Response.json({ cliente });
}

View file

@ -0,0 +1,24 @@
import { Modello, PrismaClient } from "@/generated/prisma";
export async function POST(request: Request) {
const prisma = new PrismaClient();
const data = await request.json();
await prisma.registratore.create({
data: {
id: data.seriale,
id_cliente: data.id,
data_acquisto: new Date(data.data),
modello:
data.modello === "FORM100"
? Modello.FORM100
: data.modello === "FORM200"
? Modello.FORM200
: data.modello === "FORM200PLUS"
? Modello.FORM200PLUS
: Modello.FORM500,
},
});
return Response.json({ message: "fatto bastardo" });
}

View file

@ -2,97 +2,49 @@
import ClientCard from "@/components/client-card";
import DeviceCard from "@/components/device-card";
import { Cliente, Intervento, Registratore } from "@/generated/prisma";
import { useSearchParams } from "next/navigation";
import { useEffect, useState, Suspense } from "react";
export default function Page() {
function ClientComponent() {
const searchParams = useSearchParams();
const client = searchParams.get("client");
const id = searchParams.get("client");
const [cliente, setCliente] = useState<Cliente>();
const [registratori, setRegistratori] = useState<Array<Registratore>>();
const clienti = [
{
name: "Savoldi Ettore",
email: "savoldi.ettore@gmail.com",
ragione_sociale: "Acconciature Uomo",
p_iva: "13407520172",
telefono: "0301547854",
sede: "Via Umberto I 60/T, Flero (BS)",
sede_url: "https://maps.app.goo.gl/9uNbw2a62ZCCjkQc7",
contratto: "https://google.com",
registratori: [
{
seriale: "80E100548745",
acquisto: "15/10/2019",
ultima_verifica: "15/10/2025",
prossima_verifica: "15/10/2026",
interventi: [
{
id: "0001",
data: "15/10/2025",
lavoro: "VERIFICA FISCALE - AGGIORNAMENTO FIRMWARE",
fattura: true,
},
{
id: "0002",
data: "28/05/2025",
lavoro: "SOSTITUZIONE DGFE",
fattura: false,
},
{
id: "0003",
data: "08/10/2024",
lavoro: "VERIFICA FISCALE",
fattura: true,
},
],
},
],
},
{
name: "Forno Tagliaferri",
email: "info@tagliaferri.it",
ragione_sociale: "Forno Tagliaferri",
p_iva: "12901475639",
telefono: "0309183573",
sede: "Via Corso dei Martiri 11, Brescia (BS)",
sede_url: "https://maps.app.goo.gl/9uNbw2a62ZCCjkQc7",
contratto: "https://google.com",
registratori: [
{
seriale: "80E1002587545",
acquisto: "24/02/2020",
ultima_verifica: "24/02/2025",
prossima_verifica: "24/02/2026",
interventi: [
{
id: "0004",
data: "24/02/2025",
lavoro: "VERIFICA FISCALE",
fattura: true,
},
{
id: "0005",
data: "06/04/2025",
lavoro: "SOSTITUZIONE DGFE",
fattura: false,
},
{
id: "0006",
data: "24/02/2025",
lavoro: "VERIFICA FISCALE - AGGIORNAMENTO FIRMWARE",
fattura: true,
},
],
},
],
},
];
useEffect(() => {
async function getCliente() {
const req = await fetch(`/api/clienti/${id}`);
const data = await req.json();
setCliente(data.cliente);
setRegistratori(data.cliente.registratori);
}
getCliente();
}, [id]);
return (
<div className="flex flex-1 flex-col gap-4 p-4">
<div className="*:data-[slot=card]:from-primary/5 *:data-[slot=card]:to-card dark:*:data-[slot=card]:bg-card grid grid-cols-1 gap-4 px-4 *:data-[slot=card]:bg-gradient-to-t *:data-[slot=card]:shadow-xs lg:px-6 @xl/main:grid-cols-2 @5xl/main:grid-cols-4">
<ClientCard client={client} />
<DeviceCard clienti={clienti} />
{cliente ? <ClientCard cliente={cliente} /> : <></>}
{registratori ? (
registratori.map((registratore) => (
<DeviceCard registratore={registratore} key={registratore.id} />
))
) : (
<></>
)}
</div>
</div>
);
}
}
export default function Page() {
return (
<Suspense
fallback={<div className="p-8 text-center">Caricamento cliente...</div>}
>
<ClientComponent />
</Suspense>
);
}

View file

@ -28,7 +28,6 @@ import {
} from "@/components/ui/table";
import { cn } from "@/lib/utils";
import { Checkbox } from "@/components/ui/checkbox";
import { useSearchParams } from "next/navigation";
export default function Page() {
return (

View file

@ -2,18 +2,41 @@
import dynamic from "next/dynamic";
import { useSearchParams } from "next/navigation";
import { useEffect, useState, Suspense } from "react";
import { Cliente } from "@/generated/prisma";
export default function Page() {
function MapContent() {
const MapWithNoSSR = dynamic(() => import("../../components/map"), {
ssr: false,
});
const [clienti, setClienti] = useState<Array<Cliente>>();
const searchParams = useSearchParams();
const client = searchParams.get("client");
useEffect(() => {
async function getClienti() {
const req = await fetch(`/api/clienti`);
const data = await req.json();
setClienti(data.clients);
}
getClienti();
}, []);
return (
<div id="map" className="w-full h-full border rounded-md m-0 p-0">
<MapWithNoSSR highlight={client} />
<MapWithNoSSR
highlight={clienti?.find((cliente) => cliente.id == +(client || -1))}
clienti={clienti || undefined}
/>
</div>
);
}
export default function Page() {
return (
<Suspense fallback={<div>Caricamento mappa...</div>}>
<MapContent />
</Suspense>
);
}

View file

@ -0,0 +1,153 @@
"use client";
import {
Dialog,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { useState } from "react";
const AddClientDialog = () => {
const [open, setOpen] = useState<Boolean>(false);
const [nome, setNome] = useState("");
const [ragione_sociale, setRagione_sociale] = useState("");
const [partita_iva, setPartita_iva] = useState("");
const [telefono, setTelefono] = useState("");
const [email, setEmail] = useState("");
const [sede, setSede] = useState("");
const [sede_url, setSede_url] = useState("");
const [contratto, setContratto] = useState("");
return (
<div>
<Dialog open={open} onOpenChange={setOpen}>
<form className="z-10">
<DialogTrigger asChild>
<Button variant="outline">Aggiungi cliente</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Aggiungi cliente</DialogTitle>
{/*<DialogDescription>
Make changes to your profile here. Click save when you&apos;re
done.
</DialogDescription>*/}
</DialogHeader>
<div className="grid gap-4">
<div className="grid gap-3">
<Label htmlFor="name">Nome</Label>
<Input
id="name"
name="name"
placeholder="Nome"
onChange={(e) => setNome(e.target.value)}
/>
</div>
<div className="grid gap-3">
<Label htmlFor="ragione_sociale">Ragione sociale</Label>
<Input
id="ragione_sociale"
name="ragione_sociale"
placeholder="Ragione sociale"
onChange={(e) => setRagione_sociale(e.target.value)}
/>
</div>
<div className="grid gap-3">
<Label htmlFor="p_iva">Partita IVA</Label>
<Input
id="p_iva"
name="p_iva"
placeholder="Partita IVA"
onChange={(e) => setPartita_iva(e.target.value)}
/>
</div>
<div className="grid gap-3">
<Label htmlFor="tel">Numero di telefono</Label>
<Input
id="tel"
name="tel"
placeholder="Numero di telefono"
onChange={(e) => setTelefono(e.target.value)}
/>
</div>
<div className="grid gap-3">
<Label htmlFor="tel">Indirizzo e-mail</Label>
<Input
id="mail"
name="mail"
placeholder="Indirizzo e-mail"
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className="grid gap-3">
<Label htmlFor="sede_desc">Sede (descrizione)</Label>
<Input
id="sede_desc"
name="sede_desc"
placeholder="Sede - descrizione"
onChange={(e) => setSede(e.target.value)}
/>
</div>
<div className="grid gap-3">
<Label htmlFor="sede_link">Sede (link GMaps)</Label>
<Input
id="sede_link"
name="sede_link"
placeholder="Sede - link"
onChange={(e) => setSede_url(e.target.value)}
/>
</div>
<div className="grid gap-3">
<Label htmlFor="contratto">Contratto (link)</Label>
<Input
id="contratto"
name="contratto"
placeholder="Contratto - link"
onChange={(e) => setContratto(e.target.value)}
/>
</div>
</div>
<DialogFooter>
<DialogClose asChild>
<Button variant="outline">Cancella</Button>
</DialogClose>
<Button
onClick={async () => {
const res = await fetch("/api/clienti", {
method: "POST",
body: JSON.stringify({
nome: nome,
ragione_sociale: ragione_sociale,
partita_iva: partita_iva,
telefono: telefono,
email: email,
sede: sede,
sede_url: sede_url,
contratto: contratto,
}),
});
if (res.status == 200) {
setOpen(false);
}
}}
type="submit"
>
Aggiungi
</Button>
</DialogFooter>
</DialogContent>
</form>
</Dialog>
</div>
);
};
export default AddClientDialog;

View file

@ -0,0 +1,117 @@
"use client";
import {
Dialog,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Plus } from "lucide-react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { useEffect, useState } from "react";
import DatePicker from "./date-picker";
import { Checkbox } from "@/components/ui/checkbox";
const AddInterventoDialog = ({ id }: { id: string }) => {
//const [nome, setNome] = useState("");
const [open, setOpen] = useState(false);
const [data, setData] = useState<Date | undefined>(new Date());
const [lavoro, setLavoro] = useState<string>("");
const [fattura, setFattura] = useState<Boolean>(false);
return (
<div>
<Dialog>
<form className="z-10">
<Tooltip>
<TooltipTrigger asChild>
<DialogTrigger asChild>
<Button variant="outline" type="button">
<Plus className="size-4" />
</Button>
</DialogTrigger>
</TooltipTrigger>
<TooltipContent>
<p>Aggiungi intervento</p>
</TooltipContent>
</Tooltip>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Aggiungi intervento</DialogTitle>
{/*<DialogDescription>
Make changes to your profile here. Click save when you&apos;re
done.
</DialogDescription>*/}
</DialogHeader>
<div className="grid gap-4">
<div className="grid gap-3">
<Label htmlFor="date">Data</Label>
<DatePicker
open={open}
setOpen={setOpen}
date={data}
setDate={setData}
/>
</div>
<div className="grid gap-3">
<Label htmlFor="lavoro">Lavoro</Label>
<Input
id="lavoro"
name="lavoro"
placeholder="Lavoro eseguito..."
onChange={(e) => setLavoro(e.target.value)}
/>
</div>
<div className="gap-3 flex items-center mt-2">
<Checkbox
id="fattura"
onCheckedChange={(checked) => {
checked === "indeterminate"
? setFattura(false)
: checked
? setFattura(true)
: setFattura(false);
}}
/>
<Label htmlFor="fattura">Fattura</Label>
</div>
</div>
<DialogFooter>
<DialogClose asChild>
<Button variant="outline">Cancella</Button>
</DialogClose>
<Button
onClick={async () =>
await fetch("/api/interventi", {
method: "POST",
body: JSON.stringify({
id: id,
data: data,
fattura: fattura,
lavoro: lavoro,
}),
})
}
type="submit"
>
Aggiungi
</Button>
</DialogFooter>
</DialogContent>
</form>
</Dialog>
</div>
);
};
export default AddInterventoDialog;

View file

@ -0,0 +1,132 @@
"use client";
import {
Dialog,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Plus } from "lucide-react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { useState } from "react";
import DatePicker from "./date-picker";
import { Checkbox } from "@/components/ui/checkbox";
import ModelPicker from "./model-picker";
const AddRegistratoreDialog = ({ id }: { id: Number }) => {
//const [nome, setNome] = useState("");
const [openData, setOpenData] = useState(false);
const [openModello, setOpenModello] = useState(false);
const [data, setData] = useState<Date | undefined>();
const [seriale, setSeriale] = useState<string>("");
const [modello, setModello] = useState<Date | undefined>();
const [fattura, setFattura] = useState<Boolean>();
const modelli = [
{
value: "FORM100",
label: "Form 100",
},
{
value: "FORM200",
label: "Form 200",
},
{
value: "FORM200PLUS",
label: "Form 200 Plus",
},
{
value: "FORM500",
label: "Form 500",
},
];
return (
<div>
<Dialog>
<form className="z-10">
<Tooltip>
<TooltipTrigger asChild>
<DialogTrigger asChild>
<Button variant="outline" type="button">
<Plus className="size-4" />
</Button>
</DialogTrigger>
</TooltipTrigger>
<TooltipContent>
<p>Aggiungi registratore</p>
</TooltipContent>
</Tooltip>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Aggiungi registratore</DialogTitle>
</DialogHeader>
<div className="grid gap-4">
<div className="grid gap-3">
<Label htmlFor="seriale">Seriale</Label>
<Input
id="seriale"
name="seriale"
placeholder="Seriale"
onChange={(e) => setSeriale(e.target.value)}
/>
</div>
<div className="grid gap-3">
<Label htmlFor="date">Data di acquisto</Label>
<DatePicker
open={openData}
setOpen={setOpenData}
date={data}
setDate={setData}
/>
</div>
<div className="grid gap-3">
<Label htmlFor="lavoro">Modello</Label>
<ModelPicker
open={openModello}
setOpen={setOpenModello}
value={modello}
setValue={setModello}
modelli={modelli}
/>
</div>
</div>
<DialogFooter>
<DialogClose asChild>
<Button variant="outline">Cancella</Button>
</DialogClose>
<Button
onClick={async () =>
await fetch("/api/registratori", {
method: "POST",
body: JSON.stringify({
id: id,
seriale: seriale,
data: data,
modello: modello,
}),
})
}
type="submit"
>
Aggiungi
</Button>
</DialogFooter>
</DialogContent>
</form>
</Dialog>
</div>
);
};
export default AddRegistratoreDialog;

View file

@ -26,18 +26,8 @@ import {
} from "@/components/ui/tooltip";
import { Button } from "@/components/ui/button";
import { XIcon } from "lucide-react";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import AddClientDialog from "./add-client";
import { Cliente } from "@/generated/prisma";
const data = {
user: {
@ -68,8 +58,8 @@ const data = {
url: "/client",
icon: Home,
isVisible: false,
}
],
},
] /*
clienti: [
{
name: "Savoldi Ettore",
@ -141,24 +131,30 @@ const data = {
},
],
},
],
],*/,
};
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
const pathname = usePathname();
const router = useRouter();
const [clientPathname, setClientPathname] = useState("");
const [clienti, setClienti] = React.useState(data.clienti);
const [clienti, setClienti] = useState<Array<Cliente>>();
const { setOpen } = useSidebar();
useEffect(() => {
(async () => {
const data = await fetch("/api/clienti");
const x = await data.json();
console.log(x.clients);
setClienti(x.clients);
console.log(clienti);
})();
}, []);
useEffect(() => {
setClientPathname(pathname);
}, [pathname]);
useEffect(() => {
console.log();
}, [clientPathname]);
return (
<Sidebar
collapsible="icon"
@ -207,34 +203,25 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
return;
}
return (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton
tooltip={{
children: item.title,
hidden: false,
}}
onClick={() => {
const clienti = data.clienti.sort(
() => Math.random() - 0.5,
);
setClienti(
clienti.slice(
0,
Math.max(5, Math.floor(Math.random() * 10) + 1),
),
);
setOpen(true);
if (clientPathname != item.url) {
router.push(item.url);
}
}}
isActive={clientPathname === item.url}
className="px-2.5 md:px-2"
>
<item.icon />
<span>{item.title}</span>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem key={item.title}>
<SidebarMenuButton
tooltip={{
children: item.title,
hidden: false,
}}
onClick={() => {
setOpen(true);
if (clientPathname != item.url) {
router.push(item.url);
}
}}
isActive={clientPathname === item.url}
className="px-2.5 md:px-2"
>
<item.icon />
<span>{item.title}</span>
</SidebarMenuButton>
</SidebarMenuItem>
);
})}
</SidebarMenu>
@ -257,99 +244,53 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
</div>
</div>
<div className="flex flex-row max-h-max gap-2">
<SidebarInput placeholder="Digita per cercare..." className="h-full" />
<SidebarInput
placeholder="Digita per cercare..."
className="h-full"
/>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline" onClick={() => {
<Button
variant="outline"
onClick={() => {
if (clientPathname.split("/")[1] == "map") {
router.replace('/map', undefined);
router.replace("/map", undefined);
}
}}>
<XIcon className="size-4" />
</Button>
}}
>
<XIcon className="size-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Resetta ricerca</p>
<p>Resetta ricerca</p>
</TooltipContent>
</Tooltip>
</div>
<div>
<Dialog>
<form className="z-10">
<DialogTrigger asChild>
<Button variant="outline">Aggiungi cliente</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Aggiungi cliente</DialogTitle>
{/*<DialogDescription>
Make changes to your profile here. Click save when you&apos;re
done.
</DialogDescription>*/}
</DialogHeader>
<div className="grid gap-4">
<div className="grid gap-3">
<Label htmlFor="name">Nome</Label>
<Input id="name" name="name" placeholder="Nome" />
</div>
<div className="grid gap-3">
<Label htmlFor="ragione_sociale">Ragione sociale</Label>
<Input id="ragione_sociale" name="ragione_sociale" placeholder="Ragione sociale" />
</div>
<div className="grid gap-3">
<Label htmlFor="p_iva">Partita IVA</Label>
<Input id="p_iva" name="p_iva" placeholder="Partita IVA" />
</div>
<div className="grid gap-3">
<Label htmlFor="tel">Numero di telefono</Label>
<Input id="tel" name="tel" placeholder="Numero di telefono" />
</div>
<div className="grid gap-3">
<Label htmlFor="sede_desc">Sede (descrizione)</Label>
<Input id="sede_desc" name="sede_desc" placeholder="Sede - descrizione" />
</div>
<div className="grid gap-3">
<Label htmlFor="sede_link">Sede (link GMaps)</Label>
<Input id="sede_link" name="sede_link" placeholder="Sede - link" />
</div>
<div className="grid gap-3">
<Label htmlFor="contratto">Contratto (link)</Label>
<Input id="contratto" name="contratto" placeholder="Contratto - link" />
</div>
</div>
<DialogFooter>
<DialogClose asChild>
<Button variant="outline">Cancella</Button>
</DialogClose>
<Button type="submit">Aggiungi</Button>
</DialogFooter>
</DialogContent>
</form>
</Dialog>
</div>
<AddClientDialog />
</SidebarHeader>
<SidebarContent>
<SidebarGroup className="px-0">
<SidebarGroupContent className="">
{clienti.map((cliente) => (
{clienti?.map((cliente) => (
<span
onClick={() => {
let path = clientPathname.split("/")[1];
if (path == "dashboard") {
path = "client"
if (path == "dashboard" || path == "") {
path = "client";
}
router.push(`/${path}?client=${cliente.name}`)
router.push(`/${path}?client=${cliente.id}`);
}}
key={cliente.name}
key={cliente.id}
className="hover:cursor-pointer w-11/12 mx-auto rounded-md hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex flex-col items-start gap-2 border-b p-4 text-sm leading-tight whitespace-nowrap last:border-b-0"
>
<span className="font-medium">{cliente.name}</span>
<span className="font-medium">{cliente.ragione_sociale}</span>
<div className="flex w-full items-center gap-2">
<span className="text-xs">{cliente.sede}</span>
<span className="text-xs">
{cliente.sede.length > 35
? cliente.sede.substring(0, 35) + "..."
: cliente.sede}
</span>
</div>
<span className="line-clamp-2 w-[260px] text-xs whitespace-break-spaces">
{cliente.registratori[0].prossima_verifica}
</span>
</span>
))}
</SidebarGroupContent>

View file

@ -1,96 +1,81 @@
import {
Card,
CardAction,
CardContent,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Button } from "@/components/ui/button";
import { Edit, Plus } from "lucide-react";
const ClientCard = ({client}: {client: any}) => {
return (
<Card className="@container/card">
<CardHeader>
<CardTitle className="text-xl font-semibold tabular-nums @[250px]/card:text-2xl">
{client}
</CardTitle>
<CardAction className="flex items-center gap-4">
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">
<Edit className="size-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Modifica dettagli</p>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">
<Plus className="size-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Aggiungi registratore</p>
</TooltipContent>
</Tooltip>
</CardAction>
</CardHeader>
<CardContent className="flex items-start gap-20 text-md">
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Ragione Sociale</div>
<div className="line-clamp-1 flex gap-2 font-medium">
Acconciature Uomo
</div>
</div>
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Partita IVA</div>
<div className="line-clamp-1 flex gap-2 font-medium">
13407520172
</div>
</div>
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">
Numero di Telefono
</div>
<div className="line-clamp-1 flex gap-2 font-medium">
0301547854
</div>
</div>
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Sede</div>
<div className="line-clamp-1 flex gap-2 font-medium">
<a
className="text-blue-700 italic underline"
target="blank"
href="https://maps.app.goo.gl/9uNbw2a62ZCCjkQc7"
>
Via Umberto I 60/T, Flero (BS)
</a>
</div>
</div>
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Contratto</div>
<div className="line-clamp-1 flex gap-2 font-medium">
<a
className="text-blue-700 italic underline"
target="blank"
href="https://google.com"
>
LINK
</a>
</div>
</div>
</CardContent>
</Card>
)
}
export default ClientCard;
import {
Card,
CardAction,
CardContent,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Button } from "@/components/ui/button";
import { Edit, Plus } from "lucide-react";
import { Cliente } from "@/generated/prisma";
import AddRegistratoreDialog from "./add-registratore";
const ClientCard = ({ cliente }: { cliente: Cliente }) => {
return (
<Card className="@container/card">
<CardHeader>
<CardTitle className="text-xl font-semibold tabular-nums @[250px]/card:text-2xl">
{cliente.ragione_sociale}
</CardTitle>
<CardAction className="flex items-center gap-4">
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">
<Edit className="size-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Modifica dettagli</p>
</TooltipContent>
</Tooltip>
<AddRegistratoreDialog id={cliente.id} />
</CardAction>
</CardHeader>
<CardContent className="flex items-start gap-20 text-md">
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Partita IVA</div>
<div className="line-clamp-1 flex gap-2 font-medium">
{cliente.partita_iva}
</div>
</div>
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Numero di Telefono</div>
<div className="line-clamp-1 flex gap-2 font-medium">
{cliente.telefono}
</div>
</div>
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Sede</div>
<div className="line-clamp-1 flex gap-2 font-medium">
<a
className="text-blue-700 italic underline"
target="blank"
href={cliente.sede_url}
>
{cliente.sede}
</a>
</div>
</div>
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Contratto</div>
<div className="line-clamp-1 flex gap-2 font-medium">
<a
className="text-blue-700 italic underline"
target="blank"
href={cliente.contratto}
>
LINK
</a>
</div>
</div>
</CardContent>
</Card>
);
};
export default ClientCard;

View file

@ -0,0 +1,49 @@
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { Calendar } from "@/components/ui/calendar";
import { Button } from "@/components/ui/button";
import { ChevronDownIcon } from "lucide-react";
import { Dispatch, SetStateAction } from "react";
const DatePicker = ({
open,
setOpen,
date,
setDate,
}: {
open: boolean;
setOpen: Dispatch<SetStateAction<boolean>>;
date: Date | undefined;
setDate: Dispatch<SetStateAction<Date | undefined>>;
}) => {
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
id="date"
className="w-full justify-between font-normal"
>
{date ? date.toLocaleDateString() : "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="start">
<Calendar
mode="single"
selected={date}
captionLayout="dropdown"
onSelect={(date) => {
setDate(date);
setOpen(false);
}}
/>
</PopoverContent>
</Popover>
);
};
export default DatePicker;

View file

@ -1,169 +1,138 @@
import {
Card,
CardAction,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Button } from "@/components/ui/button";
import { Edit, Plus } from "lucide-react";
import { Checkbox } from "@/components/ui/checkbox";
import { cn } from "@/lib/utils";
import { useSearchParams } from "next/navigation";
type Invervento = {
id: string,
data: string,
lavoro: string,
fattura: boolean
}
type Registratore = {
seriale: string,
acquisto: string,
ultima_verifica: string,
prossima_verifica: string,
interventi: Array<Invervento>
}
type Cliente = {
name: string,
email: string,
ragione_sociale: string,
p_iva: string,
telefono: string,
sede: string,
sede_url: string,
contratto: string,
registratori: Array<Registratore>
}
const DeviceCard = ({clienti}: {clienti:Array<Cliente>}) => {
const searchParams = useSearchParams();
const client = searchParams.get("client");
return (
<Card className="@container/card">
<CardHeader>
<CardTitle className="text-xl font-semibold tabular-nums @[250px]/card:text-2xl">
FORM 100
</CardTitle>
<CardAction className="flex items-center gap-4">
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">
<Edit className="size-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Modifica dettagli</p>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">
<Plus className="size-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Aggiungi intervento</p>
</TooltipContent>
</Tooltip>
</CardAction>
</CardHeader>
<CardContent className="flex flex-col gap-5 text-md">
<div className="flex items-start gap-20 text-md">
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Seriale</div>
<div className="line-clamp-1 flex gap-2 font-medium">
80E100548745
</div>
</div>
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Data acquisto</div>
<div className="line-clamp-1 flex gap-2 font-medium">
15/10/2019
</div>
</div>
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Ultima verifica</div>
<div className="line-clamp-1 flex gap-2 font-medium">
15/10/2025
</div>
</div>
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">
Prossima verifica
</div>
<div className="line-clamp-1 flex gap-2 font-medium">
15/10/2026
</div>
</div>
</div>
<div className="flex flex-col">
<Table className={cn("caption-top")}>
<TableCaption className="text-lg text-start">
Lista interventi
</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Data</TableHead>
<TableHead>Lavoro</TableHead>
<TableHead className="text-right">Fattura</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{clienti
.find(
(cliente) =>
cliente.name == decodeURIComponent(client?.toString() || ""),
)
?.registratori[0].interventi.map((intervento) => (
<TableRow key={intervento.id}>
<TableCell className="font-medium">
{intervento.data}
</TableCell>
<TableCell>{intervento.lavoro}</TableCell>
<TableCell className="text-right">
<Checkbox checked={intervento.fattura} />
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</CardContent>
<CardFooter className="flex gap-5">
<Button
variant="destructive"
className="hover:bg-red-800 transition-colors"
>
DISMETTI
</Button>
<Button
variant="destructive"
className="hover:bg-red-800 transition-colors"
>
ROTTAMA
</Button>
</CardFooter>
</Card>
)
}
export default DeviceCard;
"use client";
import {
Card,
CardAction,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Button } from "@/components/ui/button";
import { Edit, Plus } from "lucide-react";
import { Checkbox } from "@/components/ui/checkbox";
import { cn } from "@/lib/utils";
import { Cliente, Registratore } from "@/generated/prisma";
import AddInterventoDialog from "./add-intervento";
const DeviceCard = ({ registratore }: { registratore: Registratore }) => {
return (
<Card className="@container/card">
<CardHeader>
<CardTitle className="text-xl font-semibold tabular-nums @[250px]/card:text-2xl">
{registratore.modello}
</CardTitle>
<CardAction className="flex items-center gap-4">
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">
<Edit className="size-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Modifica dettagli</p>
</TooltipContent>
</Tooltip>
<AddInterventoDialog id={registratore.id} />
</CardAction>
</CardHeader>
<CardContent className="flex flex-col gap-5 text-md">
<div className="flex items-start gap-20 text-md">
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Seriale</div>
<div className="line-clamp-1 flex gap-2 font-medium">
{registratore.id}
</div>
</div>
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Data acquisto</div>
<div className="line-clamp-1 flex gap-2 font-medium">
{registratore.data_acquisto
? new Date(registratore.data_acquisto).toLocaleDateString(
"it-IT",
)
: "--"}
</div>
</div>
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Ultima verifica</div>
<div className="line-clamp-1 flex gap-2 font-medium">
{registratore.ultima_verifica
? new Date(registratore.ultima_verifica).toLocaleDateString(
"it-IT",
)
: "--"}
</div>
</div>
<div className="flex-col items-start gap-1.5 text-md">
<div className="text-muted-foreground">Prossima verifica</div>
<div className="line-clamp-1 flex gap-2 font-medium">
{registratore.prossima_verifica
? new Date(registratore.prossima_verifica).toLocaleDateString(
"it-IT",
)
: "--"}
</div>
</div>
</div>
<div className="flex flex-col">
<Table className={cn("caption-top")}>
<TableCaption className="text-lg text-start">
Lista interventi
</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Data</TableHead>
<TableHead>Lavoro</TableHead>
<TableHead className="text-right">Fattura</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{registratore.interventi.map((intervento) => (
<TableRow key={intervento.id}>
<TableCell className="font-medium">
{new Date(intervento.data).toLocaleDateString("it-IT")}
</TableCell>
<TableCell>{intervento.lavoro}</TableCell>
<TableCell className="text-right">
<Checkbox checked={intervento.fattura} />
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</CardContent>
<CardFooter className="flex gap-5">
<Button
variant="destructive"
className="hover:bg-red-800 transition-colors"
>
DISMETTI
</Button>
<Button
variant="destructive"
className="hover:bg-red-800 transition-colors"
>
ROTTAMA
</Button>
</CardFooter>
</Card>
);
};
export default DeviceCard;

View file

@ -8,8 +8,15 @@ import {
} from "@/components/ui/tooltip";
import { Button } from "@/components/ui/button";
import { Map as MapIcon } from "lucide-react";
import { Cliente } from "@/generated/prisma";
const Map = ({highlight}: {highlight?: string}) => {
const Map = ({
highlight,
clienti,
}: {
highlight?: Cliente;
clienti?: Array<Cliente>;
}) => {
const positions = [
{
name: "Autogeneral",
@ -38,9 +45,6 @@ const Map = ({highlight}: {highlight?: string}) => {
},
];
console.log(highlight);
console.log(positions.find((client) => client.name == highlight));
const customMarker = new Icon({
iconUrl: "marker-icon-red.png",
iconAnchor: [10, 20],
@ -49,7 +53,11 @@ const Map = ({highlight}: {highlight?: string}) => {
return (
<MapContainer
center={highlight ? positions.find((client) => client.name == highlight)?.position : [45.54157745559809, 10.211896906975962]}
center={
highlight
? [highlight.lat, highlight.lon]
: [45.54157745559809, 10.211896906975962]
}
zoom={13}
scrollWheelZoom={true}
className="m-0 p-0 h-[99%] w-[99%] mx-[0.5%] my-[0.5%] rounded-md z-0"
@ -58,9 +66,50 @@ const Map = ({highlight}: {highlight?: string}) => {
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url={`https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png`}
/>
{ highlight == null ? positions.map((client) => (
{highlight == null ? (
clienti ? (
clienti.map((client) => (
<Marker
position={[client.lat, client.lon]}
draggable={false}
animate={false}
icon={customMarker}
key={client.id}
>
<Popup className="">
<div className="flex flex-row gap-5">
<div>
<span className="block text-sm font-bold">
{client.ragione_sociale}
</span>
<div className="flex gap-2">
<span className="text-xs font-semibold">P.IVA</span>
<span className="text-xs">{client.partita_iva}</span>
</div>
</div>
<Tooltip>
<TooltipTrigger asChild>
<a href={client.sede_url} target="blank">
<Button variant="outline">
<MapIcon className="size-4" />
</Button>
</a>
</TooltipTrigger>
<TooltipContent>
<p>Resetta ricerca</p>
</TooltipContent>
</Tooltip>
</div>
</Popup>
</Marker>
))
) : (
<></>
)
) : (
<Marker
position={client.position}
position={[highlight.lat, highlight.lon]}
draggable={false}
animate={false}
icon={customMarker}
@ -68,7 +117,9 @@ const Map = ({highlight}: {highlight?: string}) => {
<Popup className="">
<div className="flex flex-row gap-5">
<div>
<span className="block text-sm font-bold">{client.name}</span>
<span className="block text-sm font-bold">
{highlight.ragione_sociale}
</span>
<div className="flex gap-2">
<span className="text-xs font-semibold">P.IVA</span>
<span className="text-xs">03417520172</span>
@ -77,52 +128,20 @@ const Map = ({highlight}: {highlight?: string}) => {
<Tooltip>
<TooltipTrigger asChild>
<a href={client.sede_url} target="blank">
<Button variant="outline">
<MapIcon className="size-4" />
</Button>
</a>
<a href={highlight.sede_url} target="blank">
<Button variant="outline">
<MapIcon className="size-4" />
</Button>
</a>
</TooltipTrigger>
<TooltipContent>
<p>Resetta ricerca</p>
<p>Resetta ricerca</p>
</TooltipContent>
</Tooltip>
</div>
</Popup>
</Marker>
)) :
<Marker
position={positions.find((client) => client.name == highlight)?.position}
draggable={false}
animate={false}
icon={customMarker}
>
<Popup className="">
<div className="flex flex-row gap-5">
<div>
<span className="block text-sm font-bold">{positions.find((client) => client.name == highlight)?.name}</span>
<div className="flex gap-2">
<span className="text-xs font-semibold">P.IVA</span>
<span className="text-xs">03417520172</span>
</div>
</div>
<Tooltip>
<TooltipTrigger asChild>
<a href={positions.find((client) => client.name == highlight)?.sede_url} target="blank">
<Button variant="outline">
<MapIcon className="size-4" />
</Button>
</a>
</TooltipTrigger>
<TooltipContent>
<p>Resetta ricerca</p>
</TooltipContent>
</Tooltip>
</div>
</Popup>
</Marker>
}
)}
</MapContainer>
);
};

View file

@ -0,0 +1,79 @@
import { Check, ChevronsUpDown } from "lucide-react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { Dispatch, SetStateAction } from "react";
const ModelPicker = ({
open,
setOpen,
value,
setValue,
modelli,
}: {
open: boolean;
setOpen: Dispatch<SetStateAction<boolean>>;
value: any;
setValue: Dispatch<SetStateAction<any>>;
modelli: Array<any>;
}) => {
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className="w-full justify-between"
>
{value
? modelli.find((modello) => modello.value === value)?.label
: "Select framework..."}
<ChevronsUpDown className="opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-full p-0">
<Command>
<CommandInput placeholder="Search framework..." className="h-9" />
<CommandList>
<CommandEmpty>No framework found.</CommandEmpty>
<CommandGroup>
{modelli.map((modello) => (
<CommandItem
key={modello.value}
value={modello.value}
onSelect={(currentValue) => {
setValue(currentValue === value ? "" : currentValue);
setOpen(false);
}}
>
{modello.label}
<Check
className={cn(
"ml-auto",
value === modello.value ? "opacity-100" : "opacity-0",
)}
/>
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
};
export default ModelPicker;

View file

@ -0,0 +1,216 @@
"use client"
import * as React from "react"
import {
ChevronDownIcon,
ChevronLeftIcon,
ChevronRightIcon,
} from "lucide-react"
import { DayButton, DayPicker, getDefaultClassNames } from "react-day-picker"
import { cn } from "@/lib/utils"
import { Button, buttonVariants } from "@/components/ui/button"
function Calendar({
className,
classNames,
showOutsideDays = true,
captionLayout = "label",
buttonVariant = "ghost",
formatters,
components,
...props
}: React.ComponentProps<typeof DayPicker> & {
buttonVariant?: React.ComponentProps<typeof Button>["variant"]
}) {
const defaultClassNames = getDefaultClassNames()
return (
<DayPicker
showOutsideDays={showOutsideDays}
className={cn(
"bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
className
)}
captionLayout={captionLayout}
formatters={{
formatMonthDropdown: (date) =>
date.toLocaleString("default", { month: "short" }),
...formatters,
}}
classNames={{
root: cn("w-fit", defaultClassNames.root),
months: cn(
"flex gap-4 flex-col md:flex-row relative",
defaultClassNames.months
),
month: cn("flex flex-col w-full gap-4", defaultClassNames.month),
nav: cn(
"flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between",
defaultClassNames.nav
),
button_previous: cn(
buttonVariants({ variant: buttonVariant }),
"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
defaultClassNames.button_previous
),
button_next: cn(
buttonVariants({ variant: buttonVariant }),
"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
defaultClassNames.button_next
),
month_caption: cn(
"flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)",
defaultClassNames.month_caption
),
dropdowns: cn(
"w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5",
defaultClassNames.dropdowns
),
dropdown_root: cn(
"relative has-focus:border-ring border border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] rounded-md",
defaultClassNames.dropdown_root
),
dropdown: cn(
"absolute bg-popover inset-0 opacity-0",
defaultClassNames.dropdown
),
caption_label: cn(
"select-none font-medium",
captionLayout === "label"
? "text-sm"
: "rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5",
defaultClassNames.caption_label
),
table: "w-full border-collapse",
weekdays: cn("flex", defaultClassNames.weekdays),
weekday: cn(
"text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none",
defaultClassNames.weekday
),
week: cn("flex w-full mt-2", defaultClassNames.week),
week_number_header: cn(
"select-none w-(--cell-size)",
defaultClassNames.week_number_header
),
week_number: cn(
"text-[0.8rem] select-none text-muted-foreground",
defaultClassNames.week_number
),
day: cn(
"relative w-full h-full p-0 text-center [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none",
props.showWeekNumber
? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-md"
: "[&:first-child[data-selected=true]_button]:rounded-l-md",
defaultClassNames.day
),
range_start: cn(
"rounded-l-md bg-accent",
defaultClassNames.range_start
),
range_middle: cn("rounded-none", defaultClassNames.range_middle),
range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
today: cn(
"bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",
defaultClassNames.today
),
outside: cn(
"text-muted-foreground aria-selected:text-muted-foreground",
defaultClassNames.outside
),
disabled: cn(
"text-muted-foreground opacity-50",
defaultClassNames.disabled
),
hidden: cn("invisible", defaultClassNames.hidden),
...classNames,
}}
components={{
Root: ({ className, rootRef, ...props }) => {
return (
<div
data-slot="calendar"
ref={rootRef}
className={cn(className)}
{...props}
/>
)
},
Chevron: ({ className, orientation, ...props }) => {
if (orientation === "left") {
return (
<ChevronLeftIcon className={cn("size-4", className)} {...props} />
)
}
if (orientation === "right") {
return (
<ChevronRightIcon
className={cn("size-4", className)}
{...props}
/>
)
}
return (
<ChevronDownIcon className={cn("size-4", className)} {...props} />
)
},
DayButton: CalendarDayButton,
WeekNumber: ({ children, ...props }) => {
return (
<td {...props}>
<div className="flex size-(--cell-size) items-center justify-center text-center">
{children}
</div>
</td>
)
},
...components,
}}
{...props}
/>
)
}
function CalendarDayButton({
className,
day,
modifiers,
...props
}: React.ComponentProps<typeof DayButton>) {
const defaultClassNames = getDefaultClassNames()
const ref = React.useRef<HTMLButtonElement>(null)
React.useEffect(() => {
if (modifiers.focused) ref.current?.focus()
}, [modifiers.focused])
return (
<Button
ref={ref}
variant="ghost"
size="icon"
data-day={day.date.toLocaleDateString()}
data-selected-single={
modifiers.selected &&
!modifiers.range_start &&
!modifiers.range_end &&
!modifiers.range_middle
}
data-range-start={modifiers.range_start}
data-range-end={modifiers.range_end}
data-range-middle={modifiers.range_middle}
className={cn(
"data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 dark:hover:text-accent-foreground flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md [&>span]:text-xs [&>span]:opacity-70",
defaultClassNames.day,
className
)}
{...props}
/>
)
}
export { Calendar, CalendarDayButton }

View file

@ -0,0 +1,184 @@
"use client"
import * as React from "react"
import { Command as CommandPrimitive } from "cmdk"
import { SearchIcon } from "lucide-react"
import { cn } from "@/lib/utils"
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog"
function Command({
className,
...props
}: React.ComponentProps<typeof CommandPrimitive>) {
return (
<CommandPrimitive
data-slot="command"
className={cn(
"bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
className
)}
{...props}
/>
)
}
function CommandDialog({
title = "Command Palette",
description = "Search for a command to run...",
children,
className,
showCloseButton = true,
...props
}: React.ComponentProps<typeof Dialog> & {
title?: string
description?: string
className?: string
showCloseButton?: boolean
}) {
return (
<Dialog {...props}>
<DialogHeader className="sr-only">
<DialogTitle>{title}</DialogTitle>
<DialogDescription>{description}</DialogDescription>
</DialogHeader>
<DialogContent
className={cn("overflow-hidden p-0", className)}
showCloseButton={showCloseButton}
>
<Command className="[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
{children}
</Command>
</DialogContent>
</Dialog>
)
}
function CommandInput({
className,
...props
}: React.ComponentProps<typeof CommandPrimitive.Input>) {
return (
<div
data-slot="command-input-wrapper"
className="flex h-9 items-center gap-2 border-b px-3"
>
<SearchIcon className="size-4 shrink-0 opacity-50" />
<CommandPrimitive.Input
data-slot="command-input"
className={cn(
"placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
/>
</div>
)
}
function CommandList({
className,
...props
}: React.ComponentProps<typeof CommandPrimitive.List>) {
return (
<CommandPrimitive.List
data-slot="command-list"
className={cn(
"max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto",
className
)}
{...props}
/>
)
}
function CommandEmpty({
...props
}: React.ComponentProps<typeof CommandPrimitive.Empty>) {
return (
<CommandPrimitive.Empty
data-slot="command-empty"
className="py-6 text-center text-sm"
{...props}
/>
)
}
function CommandGroup({
className,
...props
}: React.ComponentProps<typeof CommandPrimitive.Group>) {
return (
<CommandPrimitive.Group
data-slot="command-group"
className={cn(
"text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium",
className
)}
{...props}
/>
)
}
function CommandSeparator({
className,
...props
}: React.ComponentProps<typeof CommandPrimitive.Separator>) {
return (
<CommandPrimitive.Separator
data-slot="command-separator"
className={cn("bg-border -mx-1 h-px", className)}
{...props}
/>
)
}
function CommandItem({
className,
...props
}: React.ComponentProps<typeof CommandPrimitive.Item>) {
return (
<CommandPrimitive.Item
data-slot="command-item"
className={cn(
"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...props}
/>
)
}
function CommandShortcut({
className,
...props
}: React.ComponentProps<"span">) {
return (
<span
data-slot="command-shortcut"
className={cn(
"text-muted-foreground ml-auto text-xs tracking-widest",
className
)}
{...props}
/>
)
}
export {
Command,
CommandDialog,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
CommandShortcut,
CommandSeparator,
}

View file

@ -0,0 +1,48 @@
"use client"
import * as React from "react"
import * as PopoverPrimitive from "@radix-ui/react-popover"
import { cn } from "@/lib/utils"
function Popover({
...props
}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
return <PopoverPrimitive.Root data-slot="popover" {...props} />
}
function PopoverTrigger({
...props
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
}
function PopoverContent({
className,
align = "center",
sideOffset = 4,
...props
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
return (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
data-slot="popover-content"
align={align}
sideOffset={sideOffset}
className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
className
)}
{...props}
/>
</PopoverPrimitive.Portal>
)
}
function PopoverAnchor({
...props
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />
}
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }

1
src/generated/prisma/client.d.ts vendored Normal file
View file

@ -0,0 +1 @@
export * from "./index"

View file

@ -0,0 +1,4 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!!
/* eslint-disable */
module.exports = { ...require('.') }

1
src/generated/prisma/default.d.ts vendored Normal file
View file

@ -0,0 +1 @@
export * from "./index"

View file

@ -0,0 +1,4 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!!
/* eslint-disable */
module.exports = { ...require('#main-entry-point') }

1
src/generated/prisma/edge.d.ts vendored Normal file
View file

@ -0,0 +1 @@
export * from "./default"

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,209 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!!
/* eslint-disable */
Object.defineProperty(exports, "__esModule", { value: true });
const {
Decimal,
objectEnumValues,
makeStrictEnum,
Public,
getRuntime,
skip
} = require('./runtime/index-browser.js')
const Prisma = {}
exports.Prisma = Prisma
exports.$Enums = {}
/**
* Prisma Client JS version: 6.18.0
* Query Engine version: 34b5a692b7bd79939a9a2c3ef97d816e749cda2f
*/
Prisma.prismaVersion = {
client: "6.18.0",
engine: "34b5a692b7bd79939a9a2c3ef97d816e749cda2f"
}
Prisma.PrismaClientKnownRequestError = () => {
const runtimeName = getRuntime().prettyName;
throw new Error(`PrismaClientKnownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
)};
Prisma.PrismaClientUnknownRequestError = () => {
const runtimeName = getRuntime().prettyName;
throw new Error(`PrismaClientUnknownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
)}
Prisma.PrismaClientRustPanicError = () => {
const runtimeName = getRuntime().prettyName;
throw new Error(`PrismaClientRustPanicError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
)}
Prisma.PrismaClientInitializationError = () => {
const runtimeName = getRuntime().prettyName;
throw new Error(`PrismaClientInitializationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
)}
Prisma.PrismaClientValidationError = () => {
const runtimeName = getRuntime().prettyName;
throw new Error(`PrismaClientValidationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
)}
Prisma.Decimal = Decimal
/**
* Re-export of sql-template-tag
*/
Prisma.sql = () => {
const runtimeName = getRuntime().prettyName;
throw new Error(`sqltag is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
)}
Prisma.empty = () => {
const runtimeName = getRuntime().prettyName;
throw new Error(`empty is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
)}
Prisma.join = () => {
const runtimeName = getRuntime().prettyName;
throw new Error(`join is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
)}
Prisma.raw = () => {
const runtimeName = getRuntime().prettyName;
throw new Error(`raw is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
)}
Prisma.validator = Public.validator
/**
* Extensions
*/
Prisma.getExtensionContext = () => {
const runtimeName = getRuntime().prettyName;
throw new Error(`Extensions.getExtensionContext is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
)}
Prisma.defineExtension = () => {
const runtimeName = getRuntime().prettyName;
throw new Error(`Extensions.defineExtension is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
)}
/**
* Shorthand utilities for JSON filtering
*/
Prisma.DbNull = objectEnumValues.instances.DbNull
Prisma.JsonNull = objectEnumValues.instances.JsonNull
Prisma.AnyNull = objectEnumValues.instances.AnyNull
Prisma.NullTypes = {
DbNull: objectEnumValues.classes.DbNull,
JsonNull: objectEnumValues.classes.JsonNull,
AnyNull: objectEnumValues.classes.AnyNull
}
/**
* Enums
*/
exports.Prisma.TransactionIsolationLevel = makeStrictEnum({
ReadUncommitted: 'ReadUncommitted',
ReadCommitted: 'ReadCommitted',
RepeatableRead: 'RepeatableRead',
Serializable: 'Serializable'
});
exports.Prisma.InterventoScalarFieldEnum = {
id: 'id',
id_registratore: 'id_registratore',
data: 'data',
lavoro: 'lavoro',
fattura: 'fattura'
};
exports.Prisma.RegistratoreScalarFieldEnum = {
id: 'id',
id_cliente: 'id_cliente',
modello: 'modello',
data_acquisto: 'data_acquisto',
ultima_verifica: 'ultima_verifica',
prossima_verifica: 'prossima_verifica'
};
exports.Prisma.ClienteScalarFieldEnum = {
id: 'id',
ragione_sociale: 'ragione_sociale',
email: 'email',
partita_iva: 'partita_iva',
telefono: 'telefono',
sede: 'sede',
sede_url: 'sede_url',
contratto: 'contratto',
lat: 'lat',
lon: 'lon'
};
exports.Prisma.SortOrder = {
asc: 'asc',
desc: 'desc'
};
exports.Prisma.QueryMode = {
default: 'default',
insensitive: 'insensitive'
};
exports.Prisma.NullsOrder = {
first: 'first',
last: 'last'
};
exports.Modello = exports.$Enums.Modello = {
FORM100: 'FORM100',
FORM200: 'FORM200',
FORM200PLUS: 'FORM200PLUS',
FORM500: 'FORM500'
};
exports.Prisma.ModelName = {
Intervento: 'Intervento',
Registratore: 'Registratore',
Cliente: 'Cliente'
};
/**
* This is a stub Prisma Client that will error at runtime if called.
*/
class PrismaClient {
constructor() {
return new Proxy(this, {
get(target, prop) {
let message
const runtime = getRuntime()
if (runtime.isEdge) {
message = `PrismaClient is not configured to run in ${runtime.prettyName}. In order to run Prisma Client on edge runtime, either:
- Use Prisma Accelerate: https://pris.ly/d/accelerate
- Use Driver Adapters: https://pris.ly/d/driver-adapters
`;
} else {
message = 'PrismaClient is unable to run in this browser environment, or has been bundled for the browser (running in `' + runtime.prettyName + '`).'
}
message += `
If this is unexpected, please open an issue: https://pris.ly/prisma-prisma-bug-report`
throw new Error(message)
}
})
}
}
exports.PrismaClient = PrismaClient
Object.assign(exports, Prisma)

6049
src/generated/prisma/index.d.ts vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,183 @@
{
"name": "prisma-client-5f7d234f39789de56f24e3f97fcb730daf5c78fb0ef54bab42a661559a87fb78",
"main": "index.js",
"types": "index.d.ts",
"browser": "default.js",
"exports": {
"./client": {
"require": {
"node": "./index.js",
"edge-light": "./wasm.js",
"workerd": "./wasm.js",
"worker": "./wasm.js",
"browser": "./index-browser.js",
"default": "./index.js"
},
"import": {
"node": "./index.js",
"edge-light": "./wasm.js",
"workerd": "./wasm.js",
"worker": "./wasm.js",
"browser": "./index-browser.js",
"default": "./index.js"
},
"default": "./index.js"
},
"./package.json": "./package.json",
".": {
"require": {
"node": "./index.js",
"edge-light": "./wasm.js",
"workerd": "./wasm.js",
"worker": "./wasm.js",
"browser": "./index-browser.js",
"default": "./index.js"
},
"import": {
"node": "./index.js",
"edge-light": "./wasm.js",
"workerd": "./wasm.js",
"worker": "./wasm.js",
"browser": "./index-browser.js",
"default": "./index.js"
},
"default": "./index.js"
},
"./edge": {
"types": "./edge.d.ts",
"require": "./edge.js",
"import": "./edge.js",
"default": "./edge.js"
},
"./react-native": {
"types": "./react-native.d.ts",
"require": "./react-native.js",
"import": "./react-native.js",
"default": "./react-native.js"
},
"./extension": {
"types": "./extension.d.ts",
"require": "./extension.js",
"import": "./extension.js",
"default": "./extension.js"
},
"./index-browser": {
"types": "./index.d.ts",
"require": "./index-browser.js",
"import": "./index-browser.js",
"default": "./index-browser.js"
},
"./index": {
"types": "./index.d.ts",
"require": "./index.js",
"import": "./index.js",
"default": "./index.js"
},
"./wasm": {
"types": "./wasm.d.ts",
"require": "./wasm.js",
"import": "./wasm.mjs",
"default": "./wasm.mjs"
},
"./runtime/client": {
"types": "./runtime/client.d.ts",
"node": {
"require": "./runtime/client.js",
"default": "./runtime/client.js"
},
"require": "./runtime/client.js",
"import": "./runtime/client.mjs",
"default": "./runtime/client.mjs"
},
"./runtime/library": {
"types": "./runtime/library.d.ts",
"require": "./runtime/library.js",
"import": "./runtime/library.mjs",
"default": "./runtime/library.mjs"
},
"./runtime/binary": {
"types": "./runtime/binary.d.ts",
"require": "./runtime/binary.js",
"import": "./runtime/binary.mjs",
"default": "./runtime/binary.mjs"
},
"./runtime/wasm-engine-edge": {
"types": "./runtime/wasm-engine-edge.d.ts",
"require": "./runtime/wasm-engine-edge.js",
"import": "./runtime/wasm-engine-edge.mjs",
"default": "./runtime/wasm-engine-edge.mjs"
},
"./runtime/wasm-compiler-edge": {
"types": "./runtime/wasm-compiler-edge.d.ts",
"require": "./runtime/wasm-compiler-edge.js",
"import": "./runtime/wasm-compiler-edge.mjs",
"default": "./runtime/wasm-compiler-edge.mjs"
},
"./runtime/edge": {
"types": "./runtime/edge.d.ts",
"require": "./runtime/edge.js",
"import": "./runtime/edge-esm.js",
"default": "./runtime/edge-esm.js"
},
"./runtime/react-native": {
"types": "./runtime/react-native.d.ts",
"require": "./runtime/react-native.js",
"import": "./runtime/react-native.js",
"default": "./runtime/react-native.js"
},
"./runtime/index-browser": {
"types": "./runtime/index-browser.d.ts",
"require": "./runtime/index-browser.js",
"import": "./runtime/index-browser.mjs",
"default": "./runtime/index-browser.mjs"
},
"./generator-build": {
"require": "./generator-build/index.js",
"import": "./generator-build/index.js",
"default": "./generator-build/index.js"
},
"./sql": {
"require": {
"types": "./sql.d.ts",
"node": "./sql.js",
"default": "./sql.js"
},
"import": {
"types": "./sql.d.ts",
"node": "./sql.mjs",
"default": "./sql.mjs"
},
"default": "./sql.js"
},
"./*": "./*"
},
"version": "6.18.0",
"sideEffects": false,
"imports": {
"#wasm-engine-loader": {
"edge-light": "./wasm-edge-light-loader.mjs",
"workerd": "./wasm-worker-loader.mjs",
"worker": "./wasm-worker-loader.mjs",
"default": "./wasm-worker-loader.mjs"
},
"#main-entry-point": {
"require": {
"node": "./index.js",
"edge-light": "./wasm.js",
"workerd": "./wasm.js",
"worker": "./wasm.js",
"browser": "./index-browser.js",
"default": "./index.js"
},
"import": {
"node": "./index.js",
"edge-light": "./wasm.js",
"workerd": "./wasm.js",
"worker": "./wasm.js",
"browser": "./index-browser.js",
"default": "./index.js"
},
"default": "./index.js"
}
}
}

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,370 @@
declare class AnyNull extends NullTypesEnumValue {
#private;
}
declare type Args<T, F extends Operation> = T extends {
[K: symbol]: {
types: {
operations: {
[K in F]: {
args: any;
};
};
};
};
} ? T[symbol]['types']['operations'][F]['args'] : any;
declare class DbNull extends NullTypesEnumValue {
#private;
}
export declare function Decimal(n: Decimal.Value): Decimal;
export declare namespace Decimal {
export type Constructor = typeof Decimal;
export type Instance = Decimal;
export type Rounding = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
export type Modulo = Rounding | 9;
export type Value = string | number | Decimal;
// http://mikemcl.github.io/decimal.js/#constructor-properties
export interface Config {
precision?: number;
rounding?: Rounding;
toExpNeg?: number;
toExpPos?: number;
minE?: number;
maxE?: number;
crypto?: boolean;
modulo?: Modulo;
defaults?: boolean;
}
}
export declare class Decimal {
readonly d: number[];
readonly e: number;
readonly s: number;
constructor(n: Decimal.Value);
absoluteValue(): Decimal;
abs(): Decimal;
ceil(): Decimal;
clampedTo(min: Decimal.Value, max: Decimal.Value): Decimal;
clamp(min: Decimal.Value, max: Decimal.Value): Decimal;
comparedTo(n: Decimal.Value): number;
cmp(n: Decimal.Value): number;
cosine(): Decimal;
cos(): Decimal;
cubeRoot(): Decimal;
cbrt(): Decimal;
decimalPlaces(): number;
dp(): number;
dividedBy(n: Decimal.Value): Decimal;
div(n: Decimal.Value): Decimal;
dividedToIntegerBy(n: Decimal.Value): Decimal;
divToInt(n: Decimal.Value): Decimal;
equals(n: Decimal.Value): boolean;
eq(n: Decimal.Value): boolean;
floor(): Decimal;
greaterThan(n: Decimal.Value): boolean;
gt(n: Decimal.Value): boolean;
greaterThanOrEqualTo(n: Decimal.Value): boolean;
gte(n: Decimal.Value): boolean;
hyperbolicCosine(): Decimal;
cosh(): Decimal;
hyperbolicSine(): Decimal;
sinh(): Decimal;
hyperbolicTangent(): Decimal;
tanh(): Decimal;
inverseCosine(): Decimal;
acos(): Decimal;
inverseHyperbolicCosine(): Decimal;
acosh(): Decimal;
inverseHyperbolicSine(): Decimal;
asinh(): Decimal;
inverseHyperbolicTangent(): Decimal;
atanh(): Decimal;
inverseSine(): Decimal;
asin(): Decimal;
inverseTangent(): Decimal;
atan(): Decimal;
isFinite(): boolean;
isInteger(): boolean;
isInt(): boolean;
isNaN(): boolean;
isNegative(): boolean;
isNeg(): boolean;
isPositive(): boolean;
isPos(): boolean;
isZero(): boolean;
lessThan(n: Decimal.Value): boolean;
lt(n: Decimal.Value): boolean;
lessThanOrEqualTo(n: Decimal.Value): boolean;
lte(n: Decimal.Value): boolean;
logarithm(n?: Decimal.Value): Decimal;
log(n?: Decimal.Value): Decimal;
minus(n: Decimal.Value): Decimal;
sub(n: Decimal.Value): Decimal;
modulo(n: Decimal.Value): Decimal;
mod(n: Decimal.Value): Decimal;
naturalExponential(): Decimal;
exp(): Decimal;
naturalLogarithm(): Decimal;
ln(): Decimal;
negated(): Decimal;
neg(): Decimal;
plus(n: Decimal.Value): Decimal;
add(n: Decimal.Value): Decimal;
precision(includeZeros?: boolean): number;
sd(includeZeros?: boolean): number;
round(): Decimal;
sine() : Decimal;
sin() : Decimal;
squareRoot(): Decimal;
sqrt(): Decimal;
tangent() : Decimal;
tan() : Decimal;
times(n: Decimal.Value): Decimal;
mul(n: Decimal.Value) : Decimal;
toBinary(significantDigits?: number): string;
toBinary(significantDigits: number, rounding: Decimal.Rounding): string;
toDecimalPlaces(decimalPlaces?: number): Decimal;
toDecimalPlaces(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
toDP(decimalPlaces?: number): Decimal;
toDP(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
toExponential(decimalPlaces?: number): string;
toExponential(decimalPlaces: number, rounding: Decimal.Rounding): string;
toFixed(decimalPlaces?: number): string;
toFixed(decimalPlaces: number, rounding: Decimal.Rounding): string;
toFraction(max_denominator?: Decimal.Value): Decimal[];
toHexadecimal(significantDigits?: number): string;
toHexadecimal(significantDigits: number, rounding: Decimal.Rounding): string;
toHex(significantDigits?: number): string;
toHex(significantDigits: number, rounding?: Decimal.Rounding): string;
toJSON(): string;
toNearest(n: Decimal.Value, rounding?: Decimal.Rounding): Decimal;
toNumber(): number;
toOctal(significantDigits?: number): string;
toOctal(significantDigits: number, rounding: Decimal.Rounding): string;
toPower(n: Decimal.Value): Decimal;
pow(n: Decimal.Value): Decimal;
toPrecision(significantDigits?: number): string;
toPrecision(significantDigits: number, rounding: Decimal.Rounding): string;
toSignificantDigits(significantDigits?: number): Decimal;
toSignificantDigits(significantDigits: number, rounding: Decimal.Rounding): Decimal;
toSD(significantDigits?: number): Decimal;
toSD(significantDigits: number, rounding: Decimal.Rounding): Decimal;
toString(): string;
truncated(): Decimal;
trunc(): Decimal;
valueOf(): string;
static abs(n: Decimal.Value): Decimal;
static acos(n: Decimal.Value): Decimal;
static acosh(n: Decimal.Value): Decimal;
static add(x: Decimal.Value, y: Decimal.Value): Decimal;
static asin(n: Decimal.Value): Decimal;
static asinh(n: Decimal.Value): Decimal;
static atan(n: Decimal.Value): Decimal;
static atanh(n: Decimal.Value): Decimal;
static atan2(y: Decimal.Value, x: Decimal.Value): Decimal;
static cbrt(n: Decimal.Value): Decimal;
static ceil(n: Decimal.Value): Decimal;
static clamp(n: Decimal.Value, min: Decimal.Value, max: Decimal.Value): Decimal;
static clone(object?: Decimal.Config): Decimal.Constructor;
static config(object: Decimal.Config): Decimal.Constructor;
static cos(n: Decimal.Value): Decimal;
static cosh(n: Decimal.Value): Decimal;
static div(x: Decimal.Value, y: Decimal.Value): Decimal;
static exp(n: Decimal.Value): Decimal;
static floor(n: Decimal.Value): Decimal;
static hypot(...n: Decimal.Value[]): Decimal;
static isDecimal(object: any): object is Decimal;
static ln(n: Decimal.Value): Decimal;
static log(n: Decimal.Value, base?: Decimal.Value): Decimal;
static log2(n: Decimal.Value): Decimal;
static log10(n: Decimal.Value): Decimal;
static max(...n: Decimal.Value[]): Decimal;
static min(...n: Decimal.Value[]): Decimal;
static mod(x: Decimal.Value, y: Decimal.Value): Decimal;
static mul(x: Decimal.Value, y: Decimal.Value): Decimal;
static noConflict(): Decimal.Constructor; // Browser only
static pow(base: Decimal.Value, exponent: Decimal.Value): Decimal;
static random(significantDigits?: number): Decimal;
static round(n: Decimal.Value): Decimal;
static set(object: Decimal.Config): Decimal.Constructor;
static sign(n: Decimal.Value): number;
static sin(n: Decimal.Value): Decimal;
static sinh(n: Decimal.Value): Decimal;
static sqrt(n: Decimal.Value): Decimal;
static sub(x: Decimal.Value, y: Decimal.Value): Decimal;
static sum(...n: Decimal.Value[]): Decimal;
static tan(n: Decimal.Value): Decimal;
static tanh(n: Decimal.Value): Decimal;
static trunc(n: Decimal.Value): Decimal;
static readonly default?: Decimal.Constructor;
static readonly Decimal?: Decimal.Constructor;
static readonly precision: number;
static readonly rounding: Decimal.Rounding;
static readonly toExpNeg: number;
static readonly toExpPos: number;
static readonly minE: number;
static readonly maxE: number;
static readonly crypto: boolean;
static readonly modulo: Decimal.Modulo;
static readonly ROUND_UP: 0;
static readonly ROUND_DOWN: 1;
static readonly ROUND_CEIL: 2;
static readonly ROUND_FLOOR: 3;
static readonly ROUND_HALF_UP: 4;
static readonly ROUND_HALF_DOWN: 5;
static readonly ROUND_HALF_EVEN: 6;
static readonly ROUND_HALF_CEIL: 7;
static readonly ROUND_HALF_FLOOR: 8;
static readonly EUCLID: 9;
}
declare type Exact<A, W> = (A extends unknown ? (W extends A ? {
[K in keyof A]: Exact<A[K], W[K]>;
} : W) : never) | (A extends Narrowable ? A : never);
export declare function getRuntime(): GetRuntimeOutput;
declare type GetRuntimeOutput = {
id: RuntimeName;
prettyName: string;
isEdge: boolean;
};
declare class JsonNull extends NullTypesEnumValue {
#private;
}
/**
* Generates more strict variant of an enum which, unlike regular enum,
* throws on non-existing property access. This can be useful in following situations:
* - we have an API, that accepts both `undefined` and `SomeEnumType` as an input
* - enum values are generated dynamically from DMMF.
*
* In that case, if using normal enums and no compile-time typechecking, using non-existing property
* will result in `undefined` value being used, which will be accepted. Using strict enum
* in this case will help to have a runtime exception, telling you that you are probably doing something wrong.
*
* Note: if you need to check for existence of a value in the enum you can still use either
* `in` operator or `hasOwnProperty` function.
*
* @param definition
* @returns
*/
export declare function makeStrictEnum<T extends Record<PropertyKey, string | number>>(definition: T): T;
declare type Narrowable = string | number | bigint | boolean | [];
declare class NullTypesEnumValue extends ObjectEnumValue {
_getNamespace(): string;
}
/**
* Base class for unique values of object-valued enums.
*/
declare abstract class ObjectEnumValue {
constructor(arg?: symbol);
abstract _getNamespace(): string;
_getName(): string;
toString(): string;
}
export declare const objectEnumValues: {
classes: {
DbNull: typeof DbNull;
JsonNull: typeof JsonNull;
AnyNull: typeof AnyNull;
};
instances: {
DbNull: DbNull;
JsonNull: JsonNull;
AnyNull: AnyNull;
};
};
declare type Operation = 'findFirst' | 'findFirstOrThrow' | 'findUnique' | 'findUniqueOrThrow' | 'findMany' | 'create' | 'createMany' | 'createManyAndReturn' | 'update' | 'updateMany' | 'updateManyAndReturn' | 'upsert' | 'delete' | 'deleteMany' | 'aggregate' | 'count' | 'groupBy' | '$queryRaw' | '$executeRaw' | '$queryRawUnsafe' | '$executeRawUnsafe' | 'findRaw' | 'aggregateRaw' | '$runCommandRaw';
declare namespace Public {
export {
validator
}
}
export { Public }
declare type RuntimeName = 'workerd' | 'deno' | 'netlify' | 'node' | 'bun' | 'edge-light' | '';
declare function validator<V>(): <S>(select: Exact<S, V>) => S;
declare function validator<C, M extends Exclude<keyof C, `$${string}`>, O extends keyof C[M] & Operation>(client: C, model: M, operation: O): <S>(select: Exact<S, Args<C[M], O>>) => S;
declare function validator<C, M extends Exclude<keyof C, `$${string}`>, O extends keyof C[M] & Operation, P extends keyof Args<C[M], O>>(client: C, model: M, operation: O, prop: P): <S>(select: Exact<S, Args<C[M], O>[P]>) => S;
export { }

File diff suppressed because one or more lines are too long

3982
src/generated/prisma/runtime/library.d.ts vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,48 @@
generator client {
provider = "prisma-client-js"
output = "../src/generated/prisma"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum Modello {
FORM100
FORM200
FORM200PLUS
FORM500
}
model Intervento {
id Int @id @default(autoincrement())
id_registratore String
data DateTime @db.Date
lavoro String @db.Text
fattura Boolean @db.Boolean
registratore Registratore @relation(fields: [id_registratore], references: [id])
}
model Registratore {
id String @id
id_cliente Int
modello Modello?
data_acquisto DateTime? @db.Date
ultima_verifica DateTime? @db.Date
prossima_verifica DateTime? @db.Date
cliente Cliente @relation(fields: [id_cliente], references: [id])
interventi Intervento[]
}
model Cliente {
id Int @id @default(autoincrement())
ragione_sociale String @unique @db.VarChar(255)
email String @db.VarChar(255)
partita_iva String @db.VarChar(255)
telefono String @db.VarChar(255)
sede String @db.VarChar(255)
sede_url String @db.VarChar(255)
contratto String @db.VarChar(255)
registratori Registratore[]
}

View file

@ -0,0 +1,4 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!!
/* eslint-disable */
export default import('./query_engine_bg.wasm?module')

View file

@ -0,0 +1,4 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!!
/* eslint-disable */
export default import('./query_engine_bg.wasm')

1
src/generated/prisma/wasm.d.ts vendored Normal file
View file

@ -0,0 +1 @@
export * from "./default"

View file

@ -0,0 +1,229 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!!
/* eslint-disable */
Object.defineProperty(exports, "__esModule", { value: true });
const {
PrismaClientKnownRequestError,
PrismaClientUnknownRequestError,
PrismaClientRustPanicError,
PrismaClientInitializationError,
PrismaClientValidationError,
getPrismaClient,
sqltag,
empty,
join,
raw,
skip,
Decimal,
Debug,
objectEnumValues,
makeStrictEnum,
Extensions,
warnOnce,
defineDmmfProperty,
Public,
getRuntime,
createParam,
} = require('./runtime/wasm-engine-edge.js')
const Prisma = {}
exports.Prisma = Prisma
exports.$Enums = {}
/**
* Prisma Client JS version: 6.18.0
* Query Engine version: 34b5a692b7bd79939a9a2c3ef97d816e749cda2f
*/
Prisma.prismaVersion = {
client: "6.18.0",
engine: "34b5a692b7bd79939a9a2c3ef97d816e749cda2f"
}
Prisma.PrismaClientKnownRequestError = PrismaClientKnownRequestError;
Prisma.PrismaClientUnknownRequestError = PrismaClientUnknownRequestError
Prisma.PrismaClientRustPanicError = PrismaClientRustPanicError
Prisma.PrismaClientInitializationError = PrismaClientInitializationError
Prisma.PrismaClientValidationError = PrismaClientValidationError
Prisma.Decimal = Decimal
/**
* Re-export of sql-template-tag
*/
Prisma.sql = sqltag
Prisma.empty = empty
Prisma.join = join
Prisma.raw = raw
Prisma.validator = Public.validator
/**
* Extensions
*/
Prisma.getExtensionContext = Extensions.getExtensionContext
Prisma.defineExtension = Extensions.defineExtension
/**
* Shorthand utilities for JSON filtering
*/
Prisma.DbNull = objectEnumValues.instances.DbNull
Prisma.JsonNull = objectEnumValues.instances.JsonNull
Prisma.AnyNull = objectEnumValues.instances.AnyNull
Prisma.NullTypes = {
DbNull: objectEnumValues.classes.DbNull,
JsonNull: objectEnumValues.classes.JsonNull,
AnyNull: objectEnumValues.classes.AnyNull
}
/**
* Enums
*/
exports.Prisma.TransactionIsolationLevel = makeStrictEnum({
ReadUncommitted: 'ReadUncommitted',
ReadCommitted: 'ReadCommitted',
RepeatableRead: 'RepeatableRead',
Serializable: 'Serializable'
});
exports.Prisma.InterventoScalarFieldEnum = {
id: 'id',
id_registratore: 'id_registratore',
data: 'data',
lavoro: 'lavoro',
fattura: 'fattura'
};
exports.Prisma.RegistratoreScalarFieldEnum = {
id: 'id',
id_cliente: 'id_cliente',
modello: 'modello',
data_acquisto: 'data_acquisto',
ultima_verifica: 'ultima_verifica',
prossima_verifica: 'prossima_verifica'
};
exports.Prisma.ClienteScalarFieldEnum = {
id: 'id',
ragione_sociale: 'ragione_sociale',
email: 'email',
partita_iva: 'partita_iva',
telefono: 'telefono',
sede: 'sede',
sede_url: 'sede_url',
contratto: 'contratto',
lat: 'lat',
lon: 'lon'
};
exports.Prisma.SortOrder = {
asc: 'asc',
desc: 'desc'
};
exports.Prisma.QueryMode = {
default: 'default',
insensitive: 'insensitive'
};
exports.Prisma.NullsOrder = {
first: 'first',
last: 'last'
};
exports.Modello = exports.$Enums.Modello = {
FORM100: 'FORM100',
FORM200: 'FORM200',
FORM200PLUS: 'FORM200PLUS',
FORM500: 'FORM500'
};
exports.Prisma.ModelName = {
Intervento: 'Intervento',
Registratore: 'Registratore',
Cliente: 'Cliente'
};
/**
* Create the Client
*/
const config = {
"generator": {
"name": "client",
"provider": {
"fromEnvVar": null,
"value": "prisma-client-js"
},
"output": {
"value": "C:\\Users\\nicola\\Documents\\dev\\dash-registratori\\src\\generated\\prisma",
"fromEnvVar": null
},
"config": {
"engineType": "library"
},
"binaryTargets": [
{
"fromEnvVar": null,
"value": "windows",
"native": true
}
],
"previewFeatures": [],
"sourceFilePath": "C:\\Users\\nicola\\Documents\\dev\\dash-registratori\\prisma\\schema.prisma",
"isCustomOutput": true
},
"relativeEnvPaths": {
"rootEnvPath": null,
"schemaEnvPath": "../../../.env"
},
"relativePath": "../../../prisma",
"clientVersion": "6.18.0",
"engineVersion": "34b5a692b7bd79939a9a2c3ef97d816e749cda2f",
"datasourceNames": [
"db"
],
"activeProvider": "postgresql",
"inlineDatasources": {
"db": {
"url": {
"fromEnvVar": "DATABASE_URL",
"value": null
}
}
},
"inlineSchema": "generator client {\n provider = \"prisma-client-js\"\n output = \"../src/generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\nenum Modello {\n FORM100\n FORM200\n FORM200PLUS\n FORM500\n}\n\nmodel Intervento {\n id Int @id @default(autoincrement())\n id_registratore String\n data DateTime @db.Date\n lavoro String @db.Text\n fattura Boolean @db.Boolean\n registratore Registratore @relation(fields: [id_registratore], references: [id])\n}\n\nmodel Registratore {\n id String @id\n id_cliente Int\n modello Modello?\n data_acquisto DateTime? @db.Date\n ultima_verifica DateTime? @db.Date\n prossima_verifica DateTime? @db.Date\n cliente Cliente @relation(fields: [id_cliente], references: [id])\n interventi Intervento[]\n}\n\nmodel Cliente {\n id Int @id @default(autoincrement())\n ragione_sociale String @unique @db.VarChar(255)\n email String @db.VarChar(255)\n partita_iva String @db.VarChar(255)\n telefono String @db.VarChar(255)\n sede String @db.VarChar(255)\n sede_url String\n contratto String @db.VarChar(255)\n lat Float\n lon Float\n registratori Registratore[]\n}\n",
"inlineSchemaHash": "9bd9d1485d1021de6ddd08a2040ad878357151b96b361e965ef2ca00c0bca296",
"copyEngine": true
}
config.dirname = '/'
config.runtimeDataModel = JSON.parse("{\"models\":{\"Intervento\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"id_registratore\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"data\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"lavoro\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"fattura\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"registratore\",\"kind\":\"object\",\"type\":\"Registratore\",\"relationName\":\"InterventoToRegistratore\"}],\"dbName\":null},\"Registratore\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"id_cliente\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"modello\",\"kind\":\"enum\",\"type\":\"Modello\"},{\"name\":\"data_acquisto\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"ultima_verifica\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"prossima_verifica\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"cliente\",\"kind\":\"object\",\"type\":\"Cliente\",\"relationName\":\"ClienteToRegistratore\"},{\"name\":\"interventi\",\"kind\":\"object\",\"type\":\"Intervento\",\"relationName\":\"InterventoToRegistratore\"}],\"dbName\":null},\"Cliente\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"ragione_sociale\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"partita_iva\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"telefono\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sede\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sede_url\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"contratto\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"lat\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"lon\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"registratori\",\"kind\":\"object\",\"type\":\"Registratore\",\"relationName\":\"ClienteToRegistratore\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}")
defineDmmfProperty(exports.Prisma, config.runtimeDataModel)
config.engineWasm = {
getRuntime: async () => require('./query_engine_bg.js'),
getQueryEngineWasmModule: async () => {
const loader = (await import('#wasm-engine-loader')).default
const engine = (await loader).default
return engine
}
}
config.compilerWasm = undefined
config.injectableEdgeEnv = () => ({
parsed: {
DATABASE_URL: typeof globalThis !== 'undefined' && globalThis['DATABASE_URL'] || typeof process !== 'undefined' && process.env && process.env.DATABASE_URL || undefined
}
})
if (typeof globalThis !== 'undefined' && globalThis['DEBUG'] || typeof process !== 'undefined' && process.env && process.env.DEBUG || undefined) {
Debug.enable(typeof globalThis !== 'undefined' && globalThis['DEBUG'] || typeof process !== 'undefined' && process.env && process.env.DEBUG || undefined)
}
const PrismaClient = getPrismaClient(config)
exports.PrismaClient = PrismaClient
Object.assign(exports, Prisma)