Merge branch <prisma> to <main> #6
6 changed files with 35 additions and 105 deletions
18
Dockerfile
18
Dockerfile
|
|
@ -1,32 +1,26 @@
|
|||
FROM node:22-alpine AS base
|
||||
|
||||
# Dipendenze necessarie per Alpine (Prisma richiede OpenSSL)
|
||||
RUN apk add --no-cache libc6-compat openssl
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# --- STAGE 1: Installazione Dipendenze ---
|
||||
# --- STAGE 1 ---
|
||||
FROM base AS deps
|
||||
# Copia solo i file dei pacchetti per sfruttare la cache di Docker
|
||||
COPY package.json ./
|
||||
# Usa 'npm ci' invece di 'install' per build riproducibili e più veloci
|
||||
RUN npm install
|
||||
|
||||
# --- STAGE 2: Build dell'applicazione ---
|
||||
# --- STAGE 2 ---
|
||||
FROM base AS builder
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
# Genera il client Prisma PRIMA del build
|
||||
RUN npx prisma generate
|
||||
|
||||
# Disabilita la telemetria di Next.js durante il build
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
# Esegue il build (che userà output: standalone)
|
||||
RUN npm run build
|
||||
|
||||
# --- STAGE 3: Immagine di Produzione (Runner) ---
|
||||
# --- STAGE 3 ---
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
|
||||
|
|
@ -35,20 +29,14 @@ ENV NEXT_TELEMETRY_DISABLED=1
|
|||
ENV PORT=3000
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
|
||||
# Crea un utente non-root per sicurezza
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
|
||||
# Copia la cartella public (immagini, favicon, ecc.)
|
||||
COPY --from=builder /app/public ./public
|
||||
|
||||
# --- GESTIONE PRISMA E STANDALONE ---
|
||||
# Copia la cartella .next/standalone (il server ridotto)
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
# Copia gli asset statici (.next/static) nella posizione corretta
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
# Passa all'utente limitato
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ 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 } from "react";
|
||||
import { useEffect, useState, Suspense } from "react";
|
||||
|
||||
export default function Page() {
|
||||
function ClientComponent() {
|
||||
const searchParams = useSearchParams();
|
||||
const id = searchParams.get("client");
|
||||
const [cliente, setCliente] = useState<Cliente>();
|
||||
|
|
@ -23,85 +23,6 @@ export default function Page() {
|
|||
getCliente();
|
||||
}, [id]);
|
||||
|
||||
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,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
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">
|
||||
|
|
@ -117,3 +38,13 @@ export default function Page() {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<Suspense
|
||||
fallback={<div className="p-8 text-center">Caricamento cliente...</div>}
|
||||
>
|
||||
<ClientComponent />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
import dynamic from "next/dynamic";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
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,
|
||||
});
|
||||
|
|
@ -32,3 +32,11 @@ export default function Page() {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<Suspense fallback={<div>Caricamento mappa...</div>}>
|
||||
<MapContent />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ 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("");
|
||||
|
|
@ -26,7 +27,7 @@ const AddClientDialog = () => {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<Dialog>
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<form className="z-10">
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Aggiungi cliente</Button>
|
||||
|
|
@ -118,8 +119,8 @@ const AddClientDialog = () => {
|
|||
<Button variant="outline">Cancella</Button>
|
||||
</DialogClose>
|
||||
<Button
|
||||
onClick={async () =>
|
||||
await fetch("/api/clienti", {
|
||||
onClick={async () => {
|
||||
const res = await fetch("/api/clienti", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
nome: nome,
|
||||
|
|
@ -131,8 +132,12 @@ const AddClientDialog = () => {
|
|||
sede_url: sede_url,
|
||||
contratto: contratto,
|
||||
}),
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
if (res.status == 200) {
|
||||
setOpen(false);
|
||||
}
|
||||
}}
|
||||
type="submit"
|
||||
>
|
||||
Aggiungi
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ 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";
|
||||
import { Cliente, Registratore } from "@/generated/prisma";
|
||||
import AddInterventoDialog from "./add-intervento";
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue