From 18a7f9788732193224b91a026cd8a70e4edc2426 Mon Sep 17 00:00:00 2001 From: meglerhagen Date: Tue, 30 Jul 2024 08:42:48 +0200 Subject: [PATCH 1/2] before UX on tenants --- .../.content-collections/generated/index.js | 2 +- apps/www/src/actions/create-tenant.ts | 32 +-- apps/www/src/actions/delete-tenant.ts | 62 +++++ apps/www/src/actions/get-tenants.ts | 23 +- apps/www/src/actions/update-tenant.ts | 75 ++++++ .../(tenant)/tenant/[id]/building/page.tsx | 39 ++-- .../(tenant)/tenant/[id]/contract2/page.tsx | 2 +- .../src/app/(tenant)/tenant/[id]/layout.tsx | 2 +- .../www/src/app/(tenant)/tenant/[id]/page.tsx | 24 +- apps/www/src/app/(tenant)/tenant/page.tsx | 50 ++-- .../buttons/AddTenantSheet copy.tsx | 100 ++++---- .../src/components/buttons/AddTenantSheet.tsx | 56 +++-- .../components/buttons/EditTenantSheet.tsx | 220 ++++++++++++++++++ .../components/table/dashboard/columns.tsx | 32 +-- .../components/table/dashboard/data-table.tsx | 13 +- .../src/components/table/tenant/columns.tsx | 69 +++++- 16 files changed, 629 insertions(+), 172 deletions(-) create mode 100644 apps/www/src/actions/delete-tenant.ts create mode 100644 apps/www/src/actions/update-tenant.ts create mode 100644 apps/www/src/components/buttons/EditTenantSheet.tsx diff --git a/apps/www/.content-collections/generated/index.js b/apps/www/.content-collections/generated/index.js index d4369f2..f4023ce 100644 --- a/apps/www/.content-collections/generated/index.js +++ b/apps/www/.content-collections/generated/index.js @@ -1,4 +1,4 @@ -// generated by content-collections at Mon Jul 29 2024 19:17:30 GMT+0200 (Central European Summer Time) +// generated by content-collections at Tue Jul 30 2024 07:39:58 GMT+0200 (Central European Summer Time) import allDocs from "./allDocs.js"; import allMetas from "./allMetas.js"; diff --git a/apps/www/src/actions/create-tenant.ts b/apps/www/src/actions/create-tenant.ts index 4478167..d59212d 100644 --- a/apps/www/src/actions/create-tenant.ts +++ b/apps/www/src/actions/create-tenant.ts @@ -1,17 +1,17 @@ -"use server"; +"use server" -import { revalidatePath } from "next/cache"; +import { revalidatePath } from "next/cache" -import { prisma } from "@/lib/db"; -import { getCurrentUser } from "@/lib/session"; +import { prisma } from "@/lib/db" +import { getCurrentUser } from "@/lib/session" export async function createTenant(tenantData) { - const user = await getCurrentUser(); - const userId = user?.id; + const user = await getCurrentUser() + const userId = user?.id if (!userId) { - console.error("No user is currently logged in."); - return { success: false, error: "User not authenticated" }; + console.error("No user is currently logged in.") + return { success: false, error: "User not authenticated" } } try { @@ -19,10 +19,10 @@ export async function createTenant(tenantData) { const workspace = await prisma.workspace.findFirst({ where: { users: { some: { id: userId } } }, select: { id: true }, - }); + }) if (!workspace) { - throw new Error("No workspace found for this user"); + throw new Error("No workspace found for this user") } // Create a new tenant within the found workspace @@ -34,16 +34,16 @@ export async function createTenant(tenantData) { propertyId: tenantData.propertyId, buildingId: tenantData.buildingId, }, - }); + }) console.log( `Created tenant with ID: ${newTenant.id} for workspace ID: ${workspace.id}.`, - ); + ) - revalidatePath("/dashboard"); // Updates the cache for the dashboard page + revalidatePath("/tenant") - return { success: true, tenant: newTenant }; + return { success: true, tenant: newTenant } } catch (error) { - console.error(`Error creating tenant for user ID: ${userId}`, error); - return { success: false, error: error.message }; + console.error(`Error creating tenant for user ID: ${userId}`, error) + return { success: false, error: error.message } } } diff --git a/apps/www/src/actions/delete-tenant.ts b/apps/www/src/actions/delete-tenant.ts new file mode 100644 index 0000000..5e6e9be --- /dev/null +++ b/apps/www/src/actions/delete-tenant.ts @@ -0,0 +1,62 @@ +"use server" + +import { revalidatePath } from "next/cache" + +import { prisma } from "@/lib/db" +import { getCurrentUser } from "@/lib/session" + +export async function deleteTenant(tenantId: string) { + const user = await getCurrentUser() + const userId = user?.id + + if (!userId) { + console.error("No user is currently logged in.") + return { success: false, error: "User not authenticated" } + } + + try { + // Check if the tenant exists + const tenant = await prisma.tenant.findUnique({ + where: { id: tenantId }, + include: { property: true }, + }) + + if (!tenant) { + throw new Error("Tenant not found") + } + + // Check if the user has permission to delete this tenant + const userWorkspace = await prisma.workspace.findFirst({ + where: { users: { some: { id: userId } } }, + include: { properties: true }, + }) + + if ( + !userWorkspace || + !userWorkspace.properties.some((p) => p.id === tenant.propertyId) + ) { + throw new Error("You don't have permission to delete this tenant") + } + + // Delete related records first + await prisma.$transaction([ + // Delete contracts first + prisma.contract.deleteMany({ where: { tenantId } }), + // Then delete other related records + prisma.customerInvoice.deleteMany({ where: { tenantId } }), + prisma.tenantCommunications.deleteMany({ where: { tenantId } }), + prisma.contactPerson.deleteMany({ where: { tenantId } }), + // Finally, delete the tenant + prisma.tenant.delete({ where: { id: tenantId } }), + ]) + + console.log(`Deleted tenant with ID: ${tenantId}`) + + revalidatePath("/tenant") + + return { success: true } + } catch (error) { + console.error(`Error deleting tenant with ID: ${tenantId}`, error) + return { success: false, error: error.message } + } +} diff --git a/apps/www/src/actions/get-tenants.ts b/apps/www/src/actions/get-tenants.ts index 9342f25..55e6871 100644 --- a/apps/www/src/actions/get-tenants.ts +++ b/apps/www/src/actions/get-tenants.ts @@ -28,15 +28,36 @@ export async function getTenants(workspaceId: string) { officeSpace: { select: { name: true, + isRented: true, }, }, + contracts: { + select: { + baseRent: true, + startDate: true, + endDate: true, + }, + orderBy: { + startDate: "desc", + }, + take: 1, + }, }, orderBy: { name: "asc", }, }) - return { success: true, tenants } + return { + success: true, + tenants: tenants.map((tenant) => ({ + ...tenant, + isRenting: tenant.officeSpace?.isRented ?? false, + currentRent: tenant.contracts[0]?.baseRent ?? null, + contractStartDate: tenant.contracts[0]?.startDate ?? null, + contractEndDate: tenant.contracts[0]?.endDate ?? null, + })), + } } catch (error) { console.error("Error fetching tenants:", error) return { success: false, error: error.message } diff --git a/apps/www/src/actions/update-tenant.ts b/apps/www/src/actions/update-tenant.ts new file mode 100644 index 0000000..c8bbf3d --- /dev/null +++ b/apps/www/src/actions/update-tenant.ts @@ -0,0 +1,75 @@ +"use server" + +import { revalidatePath } from "next/cache" + +import { prisma } from "@/lib/db" +import { getCurrentUser } from "@/lib/session" + +export async function updateTenant( + tenantId: string, + tenantData: { + name: string + orgnr?: number | null + numEmployees: number + buildingId: string + floorId?: string | null + officeSpaceId?: string | null + propertyId: string + }, +) { + const user = await getCurrentUser() + const userId = user?.id + + if (!userId) { + console.error("No user is currently logged in.") + return { success: false, error: "User not authenticated" } + } + + try { + // Check if the tenant exists + const tenant = await prisma.tenant.findUnique({ + where: { id: tenantId }, + include: { property: true }, + }) + + if (!tenant) { + throw new Error("Tenant not found") + } + + // Check if the user has permission to update this tenant + const userWorkspace = await prisma.workspace.findFirst({ + where: { users: { some: { id: userId } } }, + include: { properties: true }, + }) + + if ( + !userWorkspace || + !userWorkspace.properties.some((p) => p.id === tenant.propertyId) + ) { + throw new Error("You don't have permission to update this tenant") + } + + // Update the tenant + const updatedTenant = await prisma.tenant.update({ + where: { id: tenantId }, + data: { + name: tenantData.name, + orgnr: tenantData.orgnr, + numEmployees: tenantData.numEmployees, + buildingId: tenantData.buildingId, + floorId: tenantData.floorId, + officeSpaceId: tenantData.officeSpaceId, + propertyId: tenantData.propertyId, + }, + }) + + console.log(`Updated tenant with ID: ${tenantId}`) + + revalidatePath("/tenant") + + return { success: true, tenant: updatedTenant } + } catch (error) { + console.error(`Error updating tenant with ID: ${tenantId}`, error) + return { success: false, error: error.message } + } +} diff --git a/apps/www/src/app/(tenant)/tenant/[id]/building/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/building/page.tsx index 29fe358..b077574 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/building/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/building/page.tsx @@ -1,6 +1,6 @@ import { getTenantDetails } from "@/actions/get-tenant-details" import { format } from "date-fns" -import { Settings } from "lucide-react" +import { Building, Settings } from "lucide-react" import { Button } from "@dingify/ui/components/button" import { @@ -61,21 +61,22 @@ export default async function BuildingTenant({ return ( - + -
+
- - {tenantDetails.building.name} - + Bygningsinformasjon
@@ -105,12 +106,10 @@ export default async function BuildingTenant({
- - {tenantDetails.property.name} - + Eiendomsinformasjon
@@ -121,6 +120,20 @@ export default async function BuildingTenant({ Navn {tenantDetails.property.name} +
  • + Adresse + + {tenantDetails.property.address || "Ikke angitt"} + +
  • +
  • + Størrelse + + {tenantDetails.property.size + ? `${tenantDetails.property.size} m²` + : "Ikke angitt"} + +
  • diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract2/page.tsx index a25a11a..b669199 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/contract2/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/contract2/page.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react" +import React from "react" import { getTenantDetails } from "@/actions/get-tenant-details" import { DashboardHeader } from "@/components/dashboard/header" diff --git a/apps/www/src/app/(tenant)/tenant/[id]/layout.tsx b/apps/www/src/app/(tenant)/tenant/[id]/layout.tsx index 47dda04..b31be84 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/layout.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/layout.tsx @@ -47,7 +47,7 @@ export default async function DashboardLayout({ }, { title: "Kontrakt v2", - href: `/tenant/${params.id}/contract2`, + href: `/tenant/${params.id}/contract2/building`, icon: "filetext", }, { diff --git a/apps/www/src/app/(tenant)/tenant/[id]/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/page.tsx index edd3ca7..38bc29d 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/page.tsx @@ -3,6 +3,7 @@ import { getTenantDetails } from "@/actions/get-tenant-details" import { Button } from "@dingify/ui/components/button" +import { AddContactPersonSheet } from "@/components/buttons/AddContactPersonSheet" import { DashboardHeader } from "@/components/dashboard/header" import { DashboardShell } from "@/components/dashboard/shell" import { EmptyPlaceholder } from "@/components/shared/empty-placeholder" @@ -26,13 +27,26 @@ export default async function TenantDetailsPage({ try { const tenantDetails = await getTenantDetails(tenantId) - if (!tenantDetails) { + if (!tenantDetails || tenantDetails.contacts.length === 0) { return ( + + + + Ingen kontaktpersoner + + + Legg til kontaktpersoner tilknyttet leietakeren. + + + ) } @@ -42,7 +56,7 @@ export default async function TenantDetailsPage({ + />
    @@ -51,7 +65,7 @@ export default async function TenantDetailsPage({ } catch (error) { return ( - + ) } diff --git a/apps/www/src/app/(tenant)/tenant/page.tsx b/apps/www/src/app/(tenant)/tenant/page.tsx index bcf6d5e..690d6bb 100644 --- a/apps/www/src/app/(tenant)/tenant/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/page.tsx @@ -1,30 +1,29 @@ -import Link from "next/link"; -import { redirect } from "next/navigation"; -import { getTenants } from "@/actions/get-tenants"; +import Link from "next/link" +import { redirect } from "next/navigation" +import { getTenants } from "@/actions/get-tenants" -import { authOptions } from "@/lib/auth"; -import { prisma } from "@/lib/db"; -import { getCurrentUser } from "@/lib/session"; -import AddTenantDropdownButton from "@/components/buttons/AddTenantDropdownButton"; -import { AddTenantSheet } from "@/components/buttons/AddTenantSheet"; -import { AddWorkspaceButton } from "@/components/buttons/AddWorkspaceButton"; -import { DashboardHeader } from "@/components/dashboard/header"; -import { DashboardShell } from "@/components/dashboard/shell"; -import { EmptyPlaceholder } from "@/components/shared/empty-placeholder"; +import { authOptions } from "@/lib/auth" +import { prisma } from "@/lib/db" +import { getCurrentUser } from "@/lib/session" +import AddTenantDropdownButton from "@/components/buttons/AddTenantDropdownButton" +import { AddTenantSheet } from "@/components/buttons/AddTenantSheet" +import { AddWorkspaceButton } from "@/components/buttons/AddWorkspaceButton" +import { DashboardHeader } from "@/components/dashboard/header" +import { DashboardShell } from "@/components/dashboard/shell" +import { EmptyPlaceholder } from "@/components/shared/empty-placeholder" import { DataTable } from "@/components/table/dashboard/data-table" import { TenantColumns } from "@/components/table/tenant/columns" export const metadata = { - title: "Dingify Dashboard - Your Alerts Overview", - description: - "Monitor and analyze all your critical events in real-time. Access key metrics, track important journeys, and make data-driven decisions to optimize your business performance on the Dingify Dashboard.", -}; + title: "Leietaker Dashboard - Din leietakeroversikt", + description: "Se og administrer alle leietakere dine på Leietaker Dashboard.", +} export default async function DashboardPage() { - const user = await getCurrentUser(); + const user = await getCurrentUser() if (!user) { - redirect(authOptions.pages?.signIn || "/login"); + redirect(authOptions.pages?.signIn || "/login") } // Fetch workspace associated with the user @@ -39,7 +38,7 @@ export default async function DashboardPage() { select: { id: true, }, - }); + }) if (!userWorkspace) { return ( @@ -57,18 +56,19 @@ export default async function DashboardPage() { - ); + ) } // Fetch tenants associated with the user's workspace - const { success, tenants = [], error } = await getTenants(userWorkspace.id); + const { success, tenants = [], error } = await getTenants(userWorkspace.id) + console.log(tenants) if (!success) { return ( - ); + ) } return ( @@ -91,11 +91,9 @@ export default async function DashboardPage() { ) : ( -
    - -
    + )}
    - ); + ) } diff --git a/apps/www/src/components/buttons/AddTenantSheet copy.tsx b/apps/www/src/components/buttons/AddTenantSheet copy.tsx index 6c183d7..3ff69ea 100644 --- a/apps/www/src/components/buttons/AddTenantSheet copy.tsx +++ b/apps/www/src/components/buttons/AddTenantSheet copy.tsx @@ -1,14 +1,14 @@ -"use client"; +"use client" -import { useEffect, useState } from "react"; -import { createTenant } from "@/actions/create-tenant"; -import { getProperties } from "@/actions/get-properties"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useForm } from "react-hook-form"; -import { toast } from "sonner"; -import { z } from "zod"; +import { useEffect, useState } from "react" +import { createTenant } from "@/actions/create-tenant" +import { getProperties } from "@/actions/get-properties" +import { zodResolver } from "@hookform/resolvers/zod" +import { useForm } from "react-hook-form" +import { toast } from "sonner" +import { z } from "zod" -import { Button } from "@dingify/ui/components/button"; +import { Button } from "@dingify/ui/components/button" import { Form, FormControl, @@ -16,15 +16,15 @@ import { FormItem, FormLabel, FormMessage, -} from "@dingify/ui/components/form"; -import { Input } from "@dingify/ui/components/input"; +} from "@dingify/ui/components/form" +import { Input } from "@dingify/ui/components/input" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@dingify/ui/components/select"; +} from "@dingify/ui/components/select" import { Sheet, SheetContent, @@ -33,21 +33,21 @@ import { SheetHeader, SheetTitle, SheetTrigger, -} from "@dingify/ui/components/sheet"; +} from "@dingify/ui/components/sheet" const TenantSchema = z.object({ - name: z.string().min(1, "Name is required"), + name: z.string().min(1, "Navn er påkrevd"), orgnr: z .string() - .min(1, "Organization number is required") - .regex(/^\d+$/, "Organization number must be a number"), - numEmployees: z.number().min(1, "Number of employees is required"), + .min(1, "Organisasjonsnummer er påkrevd") + .regex(/^\d+$/, "Organisasjonsnummer må være et tall"), + numEmployees: z.number().min(1, "Antall ansatte er påkrevd"), propertyId: z.string().optional(), -}); +}) export function AddTenantSheet() { - const [isLoading, setIsLoading] = useState(false); - const [properties, setProperties] = useState([]); + const [isLoading, setIsLoading] = useState(false) + const [properties, setProperties] = useState([]) const form = useForm({ resolver: zodResolver(TenantSchema), @@ -57,18 +57,18 @@ export function AddTenantSheet() { numEmployees: 1, // Default value set to 1 propertyId: "", }, - }); + }) useEffect(() => { async function fetchProperties() { - const properties = await getProperties(); - setProperties(properties); + const properties = await getProperties() + setProperties(properties) } - fetchProperties(); - }, []); + fetchProperties() + }, []) const onSubmit = async (data: z.infer) => { - setIsLoading(true); + setIsLoading(true) try { const tenantData = { @@ -78,34 +78,36 @@ export function AddTenantSheet() { property: data.propertyId ? { connect: { id: parseInt(data.propertyId, 10) } } : undefined, - }; + } - const result = await createTenant(tenantData); + const result = await createTenant(tenantData) if (!result.success) { - throw new Error(result.error || "Failed to save tenant."); + throw new Error(result.error || "Failed to save tenant.") } - toast.success(`Tenant ${data.name} was saved.`); - form.reset(); + toast.success(`Leietaker ${data.name} ble lagret.`) + form.reset() // Optionally, refresh the page or update the state to show the new tenant } catch (error) { - toast.error(error.message); - console.error(error); + toast.error(error.message) + console.error(error) } finally { - setIsLoading(false); + setIsLoading(false) } - }; + } return ( - + - Add New Tenant - Add details for the new tenant. + Legg til ny leietaker + + Legg til detaljer for den nye leietakeren. +
    @@ -114,9 +116,9 @@ export function AddTenantSheet() { name="name" render={({ field }) => ( - Name + Navn - + @@ -127,9 +129,9 @@ export function AddTenantSheet() { name="orgnr" render={({ field }) => ( - Organization Number + Organisasjonsnummer - + @@ -140,11 +142,11 @@ export function AddTenantSheet() { name="numEmployees" render={({ field }) => ( - Number of Employees + Antall ansatte field.onChange(Number(e.target.value))} /> @@ -158,16 +160,16 @@ export function AddTenantSheet() { name="propertyId" render={({ field }) => ( - Property + Eiendom + @@ -153,9 +159,9 @@ export function AddTenantSheet() { name="orgnr" render={({ field }) => ( - Organization Number + Organisasjonsnummer - + @@ -166,11 +172,11 @@ export function AddTenantSheet() { name="numEmployees" render={({ field }) => ( - Number of Employees + Antall ansatte field.onChange(Number(e.target.value))} /> @@ -184,7 +190,7 @@ export function AddTenantSheet() { name="propertyId" render={({ field }) => ( - Property + Eiendom { field.onChange(value) @@ -227,7 +233,7 @@ export function AddTenantSheet() { > - + @@ -251,7 +257,7 @@ export function AddTenantSheet() { disabled={isLoading} className="w-full sm:w-auto" > - {isLoading ? "Saving..." : "Save new tenant"} + {isLoading ? "Lagrer..." : "Lagre ny leietaker"} diff --git a/apps/www/src/components/buttons/EditTenantSheet.tsx b/apps/www/src/components/buttons/EditTenantSheet.tsx new file mode 100644 index 0000000..7f651b4 --- /dev/null +++ b/apps/www/src/components/buttons/EditTenantSheet.tsx @@ -0,0 +1,220 @@ +import { useEffect, useState } from "react" +import { getBuildings } from "@/actions/get-buildings" +import { getProperties } from "@/actions/get-properties" +import { updateTenant } from "@/actions/update-tenant" +import { zodResolver } from "@hookform/resolvers/zod" +import { useForm } from "react-hook-form" +import { toast } from "sonner" +import { z } from "zod" + +import { Button } from "@dingify/ui/components/button" +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@dingify/ui/components/form" +import { Input } from "@dingify/ui/components/input" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@dingify/ui/components/select" +import { + Sheet, + SheetContent, + SheetDescription, + SheetFooter, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "@dingify/ui/components/sheet" + +const TenantSchema = z.object({ + name: z.string().min(1, "Navn er påkrevd"), + orgnr: z + .string() + .min(1, "Organisasjonsnummer er påkrevd") + .regex(/^\d+$/, "Organisasjonsnummer må være et tall"), + numEmployees: z.number().min(1, "Antall ansatte er påkrevd"), + propertyId: z.string().optional(), + buildingId: z.string().optional(), +}) + +interface Property { + id: string + name: string +} + +interface Building { + id: string + name: string +} + +interface EditTenantSheetProps { + tenant: { + id: string + name: string + orgnr?: number | null + numEmployees: number + buildingId: string + floorId?: string | null + officeSpaceId?: string | null + propertyId: string + } + children: React.ReactNode +} + +export function EditTenantSheet({ tenant, children }: EditTenantSheetProps) { + const [isLoading, setIsLoading] = useState(false) + const [properties, setProperties] = useState([]) + const [buildings, setBuildings] = useState([]) + const [isOpen, setIsOpen] = useState(false) + + const form = useForm({ + resolver: zodResolver(TenantSchema), + defaultValues: { + name: tenant.name, + orgnr: tenant.orgnr?.toString() || "", + numEmployees: tenant.numEmployees, + propertyId: tenant.propertyId, + buildingId: tenant.buildingId, + }, + }) + + useEffect(() => { + async function fetchProperties() { + try { + const properties = await getProperties() + setProperties(properties) + } catch (error) { + console.error("Failed to fetch properties:", error) + } + } + fetchProperties() + }, []) + + useEffect(() => { + async function fetchBuildings() { + if (tenant.propertyId) { + try { + const buildings = await getBuildings(tenant.propertyId) + setBuildings(buildings) + } catch (error) { + console.error("Failed to fetch buildings:", error) + } + } + } + fetchBuildings() + }, [tenant.propertyId]) + + const onPropertyChange = async (propertyId: string) => { + form.setValue("propertyId", propertyId) + try { + const buildings = await getBuildings(propertyId) + setBuildings(buildings) + } catch (error) { + console.error("Failed to fetch buildings:", error) + } + } + + const onSubmit = async (data: z.infer) => { + setIsLoading(true) + + try { + const tenantData = { + ...data, + orgnr: parseInt(data.orgnr, 10), + numEmployees: Number(data.numEmployees), + buildingId: data.buildingId || tenant.buildingId, // Use existing buildingId if not provided + propertyId: data.propertyId || tenant.propertyId, // Use existing propertyId if not provided + } + + const result = await updateTenant(tenant.id, tenantData) + + if (!result.success) { + throw new Error(result.error || "Kunne ikke oppdatere leietaker.") + } + + toast.success(`Leietaker ${data.name} ble oppdatert.`) + setIsOpen(false) + } catch (error) { + toast.error(error.message) + console.error(error) + } finally { + setIsLoading(false) + } + } + + return ( + + {children} + + + Rediger leietaker + + Gjør endringer i leietakerinformasjonen her. Klikk lagre når du er + ferdig. + + + +
    + + ( + + Navn + + + + + + )} + /> + ( + + Organisasjonsnummer + + + + + + )} + /> + ( + + Antall ansatte + + field.onChange(Number(e.target.value))} + /> + + + + )} + /> + + + + + +
    +
    + ) +} diff --git a/apps/www/src/components/table/dashboard/columns.tsx b/apps/www/src/components/table/dashboard/columns.tsx index 435ffa3..eb7d024 100644 --- a/apps/www/src/components/table/dashboard/columns.tsx +++ b/apps/www/src/components/table/dashboard/columns.tsx @@ -1,11 +1,11 @@ -"use client"; +"use client" -import type { ColumnDef } from "@tanstack/react-table"; -import Link from "next/link"; -import { ArrowUpDown, MoreHorizontal } from "lucide-react"; +import type { ColumnDef } from "@tanstack/react-table" +import Link from "next/link" +import { ArrowUpDown, MoreHorizontal } from "lucide-react" -import { Badge } from "@dingify/ui/components/badge"; -import { Button } from "@dingify/ui/components/button"; +import { Badge } from "@dingify/ui/components/badge" +import { Button } from "@dingify/ui/components/button" import { DropdownMenu, DropdownMenuContent, @@ -14,14 +14,14 @@ import { DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, -} from "@dingify/ui/components/dropdown-menu"; +} from "@dingify/ui/components/dropdown-menu" -import { propertyLabels, propertyStatuses } from "./propertystatus"; +import { propertyLabels, propertyStatuses } from "./propertystatus" export interface Property { - id: string; - name: string; - label?: "APARTMENT" | "HOUSE" | "CABIN" | "PROPERTY"; + id: string + name: string + label?: "APARTMENT" | "HOUSE" | "CABIN" | "PROPERTY" createdAt?: Date } @@ -40,7 +40,7 @@ export const PropertyColumns: ColumnDef[] = [ cell: ({ row }) => { const propertyLabel = propertyLabels.find( (label) => label.value === row.original.label, - ); + ) return (
    @@ -49,13 +49,13 @@ export const PropertyColumns: ColumnDef[] = [ {row.original.name}
    - ); + ) }, }, { id: "actions", cell: ({ row }) => { - const name = row.original.name; + const name = row.original.name return (
    @@ -84,7 +84,7 @@ export const PropertyColumns: ColumnDef[] = [
    - ); + ) }, }, -]; +] diff --git a/apps/www/src/components/table/dashboard/data-table.tsx b/apps/www/src/components/table/dashboard/data-table.tsx index 111d8fd..2e39b2e 100644 --- a/apps/www/src/components/table/dashboard/data-table.tsx +++ b/apps/www/src/components/table/dashboard/data-table.tsx @@ -1,19 +1,19 @@ "use client" -import { useState } from "react" import type { ColumnDef, ColumnFiltersState, SortingState, - VisibilityState + VisibilityState, } from "@tanstack/react-table" +import { useState } from "react" import { flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, - useReactTable + useReactTable, } from "@tanstack/react-table" import { format } from "date-fns" import { nb } from "date-fns/locale" @@ -35,9 +35,8 @@ import { TableRow, } from "@dingify/ui/components/table" - -import { DataTableToolbar } from "./data-table-toolbar" import InfoCard from "../info-card" +import { DataTableToolbar } from "./data-table-toolbar" interface DataTableProps { columns: ColumnDef[] @@ -54,7 +53,7 @@ interface selectedProp { export function DataTable({ columns, data, - type + type, }: DataTableProps) { const [sorting, setSorting] = useState([]) const [columnFilters, setColumnFilters] = useState([]) @@ -156,7 +155,7 @@ export function DataTable({ - + ) } diff --git a/apps/www/src/components/table/tenant/columns.tsx b/apps/www/src/components/table/tenant/columns.tsx index 4da2970..228e76d 100644 --- a/apps/www/src/components/table/tenant/columns.tsx +++ b/apps/www/src/components/table/tenant/columns.tsx @@ -2,7 +2,10 @@ import type { ColumnDef } from "@tanstack/react-table" import Link from "next/link" +import { deleteTenant } from "@/actions/delete-tenant" +import format from "date-fns/format" import { ArrowUpDown, MoreHorizontal } from "lucide-react" +import { toast } from "sonner" import { Button } from "@dingify/ui/components/button" import { @@ -15,6 +18,8 @@ import { DropdownMenuTrigger, } from "@dingify/ui/components/dropdown-menu" +import { EditTenantSheet } from "@/components/buttons/EditTenantSheet" + export interface tenants { name: string id: number @@ -29,6 +34,10 @@ export interface tenants { } | null orgnr: number | null numEmployees: number + isRenting: boolean + currentRent: number | null + contractStartDate: string | null + contractEndDate: string | null } export const TenantColumns: ColumnDef[] = [ @@ -53,10 +62,51 @@ export const TenantColumns: ColumnDef[] = [ ) }, }, + { + accessorKey: "isRenting", + header: "Renting Status", + cell: ({ row }) => ( +
    {row.getValue("isRenting") ? "Renting" : "Not Renting"}
    + ), + }, + { + accessorKey: "currentRent", + header: "Current Rent", + cell: ({ row }) => { + const amount = row.getValue("currentRent") + return amount ? `${amount.toLocaleString()} NOK` : "N/A" + }, + }, + { + accessorKey: "contractStartDate", + header: "Contract Start", + cell: ({ row }) => { + const date = row.getValue("contractStartDate") + return date ? format(new Date(date), "dd.MM.yyyy") : "N/A" + }, + }, + { + accessorKey: "contractEndDate", + header: "Contract End", + cell: ({ row }) => { + const date = row.getValue("contractEndDate") + return date ? format(new Date(date), "dd.MM.yyyy") : "N/A" + }, + }, { id: "actions", cell: ({ row }) => { const name = row.original.name + const id = row.original.id + + const handleDelete = async () => { + const result = await deleteTenant(id.toString()) + if (result.success) { + toast.success(`Leietaker "${name}" ble slettet`) + } else { + toast.error(`Kunne ikke slette leietaker "${name}"`) + } + } return (
    @@ -68,18 +118,15 @@ export const TenantColumns: ColumnDef[] = [ - Valg - Endre - navigator.clipboard.writeText(name)} - > - Kopier navn - - - View customer + Actions + + e.preventDefault()}> + Edit + + - - Delete + + Slett ⌘⌫ From 16ec0194d5ef27fc1e9a45fb68200f4e622eaaaf Mon Sep 17 00:00:00 2001 From: meglerhagen Date: Tue, 30 Jul 2024 11:03:07 +0200 Subject: [PATCH 2/2] done --- .../.content-collections/generated/index.js | 2 +- apps/www/src/actions/create-contract.ts | 79 ++++++++++------- apps/www/src/actions/get-tenant-details.ts | 2 + .../_components/BuildingFormContract.tsx | 12 ++- .../_components/ReusableFormTemplate.tsx | 0 .../{contract2 => contract}/building/page.tsx | 29 ++----- .../{contract2 => contract}/editor/page.tsx | 0 .../kpi/_components/KpiDetailsForm.tsx | 0 .../[id]/{contract2 => contract}/kpi/page.tsx | 33 +++---- .../_components/LandlordDetailsForm.tsx | 0 .../{contract2 => contract}/landlord/page.tsx | 31 +++---- .../[id]/{contract2 => contract}/layout.tsx | 24 +++--- .../mva/_components/MvaDetailsForm.tsx | 11 ++- .../[id]/{contract2 => contract}/mva/page.tsx | 32 +++---- .../(tenant)/tenant/[id]/contract/page.tsx | 26 ++---- .../_components/SummaryDetailsForm.tsx | 0 .../tenant/[id]/contract/summary/page.tsx | 43 ++++++++++ .../tenant/_components/TenantDetailsForm.tsx | 0 .../{contract2 => contract}/tenant/page.tsx | 32 +++---- .../terms/_components/TermsDetailsForm.tsx | 0 .../{contract2 => contract}/terms/page.tsx | 32 +++---- .../time/_components/TimeDetailsForm.tsx | 0 .../{contract2 => contract}/time/page.tsx | 32 +++---- .../tenant/[id]/contract2/summary/page.tsx | 64 -------------- .../[id]/{contract2 => contractxxx}/page.tsx | 26 ++++-- .../app/(tenant)/tenant/[id]/finance/page.tsx | 4 +- .../src/app/(tenant)/tenant/[id]/layout.tsx | 7 +- apps/www/src/app/(tenant)/tenant/page.tsx | 2 +- .../buttons/EditContractDetails.tsx | 14 +-- .../src/components/table/tenant/columns.tsx | 16 ++-- .../src/components/tenant/ContractCheck.tsx | 86 +++++++++++++++++++ apps/www/src/components/users/UserNavTop.tsx | 47 +++++----- 32 files changed, 353 insertions(+), 333 deletions(-) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/building/_components/BuildingFormContract.tsx (96%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/building/_components/ReusableFormTemplate.tsx (100%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/building/page.tsx (56%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/editor/page.tsx (100%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/kpi/_components/KpiDetailsForm.tsx (100%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/kpi/page.tsx (56%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/landlord/_components/LandlordDetailsForm.tsx (100%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/landlord/page.tsx (58%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/layout.tsx (81%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/mva/_components/MvaDetailsForm.tsx (92%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/mva/page.tsx (58%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/summary/_components/SummaryDetailsForm.tsx (100%) create mode 100644 apps/www/src/app/(tenant)/tenant/[id]/contract/summary/page.tsx rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/tenant/_components/TenantDetailsForm.tsx (100%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/tenant/page.tsx (58%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/terms/_components/TermsDetailsForm.tsx (100%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/terms/page.tsx (58%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/time/_components/TimeDetailsForm.tsx (100%) rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contract}/time/page.tsx (60%) delete mode 100644 apps/www/src/app/(tenant)/tenant/[id]/contract2/summary/page.tsx rename apps/www/src/app/(tenant)/tenant/[id]/{contract2 => contractxxx}/page.tsx (65%) create mode 100644 apps/www/src/components/tenant/ContractCheck.tsx diff --git a/apps/www/.content-collections/generated/index.js b/apps/www/.content-collections/generated/index.js index f4023ce..96c77f7 100644 --- a/apps/www/.content-collections/generated/index.js +++ b/apps/www/.content-collections/generated/index.js @@ -1,4 +1,4 @@ -// generated by content-collections at Tue Jul 30 2024 07:39:58 GMT+0200 (Central European Summer Time) +// generated by content-collections at Tue Jul 30 2024 11:03:01 GMT+0200 (Central European Summer Time) import allDocs from "./allDocs.js"; import allMetas from "./allMetas.js"; diff --git a/apps/www/src/actions/create-contract.ts b/apps/www/src/actions/create-contract.ts index 5aa7672..51bdf84 100644 --- a/apps/www/src/actions/create-contract.ts +++ b/apps/www/src/actions/create-contract.ts @@ -1,48 +1,63 @@ -"use server"; +"use server" -import { prisma } from "@/lib/db"; -import { getCurrentUser } from "@/lib/session"; +import { prisma } from "@/lib/db" +import { getCurrentUser } from "@/lib/session" export async function createContract(contractData) { - const user = await getCurrentUser(); - const userId = user?.id; + const user = await getCurrentUser() + const userId = user?.id if (!userId) { - console.error("No user is currently logged in."); - return { success: false, error: "User not authenticated" }; + console.error("No user is currently logged in.") + return { success: false, error: "User not authenticated" } } try { - // Fetch the user's workspace to associate the contract - const workspace = await prisma.workspace.findFirst({ - where: { users: { some: { id: userId } } }, - select: { id: true }, + // Fetch the workspace associated with the user + const userWorkspace = await prisma.workspace.findFirst({ + where: { + users: { + some: { + id: userId, + }, + }, + }, + select: { + id: true, + }, }); - if (!workspace) { - throw new Error("No workspace found for this user"); + if (!userWorkspace) { + console.error("No workspace found for this user.") + return { success: false, error: "No workspace found" } } // Create a new contract const newContract = await prisma.contract.create({ data: { - tenantId: contractData.tenantId, - propertyId: contractData.property, - buildingId: contractData.building, - floors: { - connect: { id: contractData.floor }, + workspace: { + connect: { id: userWorkspace.id } }, - officeSpaces: { - connect: { id: contractData.officeSpace }, + tenant: { + connect: { id: contractData.tenantId } + }, + property: { + connect: { id: contractData.propertyId } + }, + building: { + connect: { id: contractData.buildingId } + }, + floors: contractData.floors, + officeSpaces: contractData.officeSpaces, + contact: { + connect: { id: contractData.contactId } }, - workspaceId: workspace.id, - contactId: parseInt(contractData.contactId), // Ensure contactId is passed correctly - contactName: contractData.contactName, - contactEmail: contractData.contactEmail, - contactPhone: contractData.contactPhone, landlordOrgnr: contractData.landlordOrgnr, landlordName: contractData.landlordName, contractType: contractData.contractType, + contactName: contractData.contactName, + contactEmail: contractData.contactEmail, + contactPhone: contractData.contactPhone, startDate: contractData.startDate, endDate: contractData.endDate, negotiationDate: contractData.negotiationDate, @@ -57,15 +72,13 @@ export async function createContract(contractData) { businessCategory: contractData.businessCategory, collateral: contractData.collateral, }, - }); + }) - console.log( - `Created contract with ID: ${newContract.id} for workspace ID: ${workspace.id}.` - ); + console.log(`Created contract with ID: ${newContract.id} for workspace ID: ${userWorkspace.id}.`) - return { success: true, contract: newContract }; + return { success: true, contract: newContract } } catch (error) { - console.error(`Error creating contract for user ID: ${userId}`, error); - return { success: false, error: error.message }; + console.error(`Error creating contract for user ID: ${userId}`, error) + return { success: false, error: error.message } } -} +} \ No newline at end of file diff --git a/apps/www/src/actions/get-tenant-details.ts b/apps/www/src/actions/get-tenant-details.ts index 03f6455..774bc1e 100644 --- a/apps/www/src/actions/get-tenant-details.ts +++ b/apps/www/src/actions/get-tenant-details.ts @@ -1,5 +1,7 @@ "use server" +import { revalidatePath } from "next/cache" + import { prisma } from "@/lib/db" import { getCurrentUser } from "@/lib/session" diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/building/_components/BuildingFormContract.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/building/_components/BuildingFormContract.tsx similarity index 96% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/building/_components/BuildingFormContract.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/building/_components/BuildingFormContract.tsx index ec96702..ce47e2c 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/contract2/building/_components/BuildingFormContract.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/contract/building/_components/BuildingFormContract.tsx @@ -54,15 +54,19 @@ export function BuildingFormContract({ tenantDetails }) { property: tenantDetails?.property?.id?.toString() || "", floor: tenantDetails?.floor?.id?.toString() || "", officeSpace: tenantDetails?.officeSpace?.id?.toString() || "", - contactId: tenantDetails?.contacts[0]?.id?.toString() || "", // Assuming there's at least one contact + contactId: tenantDetails?.contacts[0]?.id?.toString() || "", }, }) useEffect(() => { if (tenantDetails?.floor?.id) { setSelectedFloor(tenantDetails.floor.id.toString()) + form.setValue("floor", tenantDetails.floor.id.toString()) } - }, [tenantDetails?.floor?.id]) + if (tenantDetails?.officeSpace?.id) { + form.setValue("officeSpace", tenantDetails.officeSpace.id.toString()) + } + }, [tenantDetails, form]) const onSubmit = async (data) => { setIsLoading(true) @@ -158,7 +162,7 @@ export function BuildingFormContract({ tenantDetails }) { )} /> - ( @@ -232,7 +236,7 @@ export function BuildingFormContract({ tenantDetails }) { )} - /> + /> */}
    diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/building/_components/ReusableFormTemplate.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/building/_components/ReusableFormTemplate.tsx similarity index 100% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/building/_components/ReusableFormTemplate.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/building/_components/ReusableFormTemplate.tsx diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/building/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/building/page.tsx similarity index 56% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/building/page.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/building/page.tsx index 027aee1..babba46 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/contract2/building/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/contract/building/page.tsx @@ -1,11 +1,9 @@ import React from "react" import { getTenantDetails } from "@/actions/get-tenant-details" -import { Card } from "@dingify/ui/components/card" - import { DashboardHeader } from "@/components/dashboard/header" import { DashboardShell } from "@/components/dashboard/shell" -import { EmptyPlaceholder } from "@/components/shared/empty-placeholder" +import { ContractCheck } from "@/components/tenant/ContractCheck" import { BuildingFormContract } from "./_components/BuildingFormContract" @@ -23,23 +21,8 @@ export default async function Home({ params }: { params: { id: string } }) { ) } - if (tenantDetails.name && parseInt(tenantDetails.name) > 0) { - return ( - - - - - Du mangler følgende - - Placeholder - - - - ) - } + const hasContract = + tenantDetails.contracts && tenantDetails.contracts.length > 0 return ( @@ -47,7 +30,11 @@ export default async function Home({ params }: { params: { id: string } }) { heading="Byggninger" text="Hvordan byggning skal leietakeren inn i?" /> - + {hasContract ? ( + + ) : ( + + )} ) } catch (error) { diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/editor/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/editor/page.tsx similarity index 100% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/editor/page.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/editor/page.tsx diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/kpi/_components/KpiDetailsForm.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/kpi/_components/KpiDetailsForm.tsx similarity index 100% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/kpi/_components/KpiDetailsForm.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/kpi/_components/KpiDetailsForm.tsx diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/kpi/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/kpi/page.tsx similarity index 56% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/kpi/page.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/kpi/page.tsx index 19d271b..cacffc3 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/contract2/kpi/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/contract/kpi/page.tsx @@ -1,11 +1,14 @@ import React from "react" +import Link from "next/link" import { getTenantDetails } from "@/actions/get-tenant-details" +import { Button } from "@dingify/ui/components/button" import { Card } from "@dingify/ui/components/card" import { DashboardHeader } from "@/components/dashboard/header" import { DashboardShell } from "@/components/dashboard/shell" import { EmptyPlaceholder } from "@/components/shared/empty-placeholder" +import { ContractCheck } from "@/components/tenant/ContractCheck" import { KpiDetailsForm } from "./_components/KpiDetailsForm" @@ -23,31 +26,17 @@ export default async function kpiPage({ params }: { params: { id: string } }) { ) } - if (tenantDetails.name && parseInt(tenantDetails.name) > 0) { - return ( - - - - - Du mangler følgende - - Placeholder - - - - ) - } + const hasContract = + tenantDetails.contracts && tenantDetails.contracts.length > 0 return ( - - + + {hasContract ? ( + + ) : ( + + )} ) } catch (error) { diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/landlord/_components/LandlordDetailsForm.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/landlord/_components/LandlordDetailsForm.tsx similarity index 100% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/landlord/_components/LandlordDetailsForm.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/landlord/_components/LandlordDetailsForm.tsx diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/landlord/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/landlord/page.tsx similarity index 58% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/landlord/page.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/landlord/page.tsx index 742bb3d..a1b3c10 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/contract2/landlord/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/contract/landlord/page.tsx @@ -1,11 +1,13 @@ import React from "react" +import Link from "next/link" import { getTenantDetails } from "@/actions/get-tenant-details" -import { Card } from "@dingify/ui/components/card" +import { Button } from "@dingify/ui/components/button" import { DashboardHeader } from "@/components/dashboard/header" import { DashboardShell } from "@/components/dashboard/shell" import { EmptyPlaceholder } from "@/components/shared/empty-placeholder" +import { ContractCheck } from "@/components/tenant/ContractCheck" import { LandlordDetailsForm } from "./_components/LandlordDetailsForm" @@ -15,7 +17,7 @@ export default async function LandlordContract({ params: { id: string } }) { const tenantId = params.id - const currentPath = `/tenant/${tenantId}/contract2/landlord` + const currentPath = `/tenant/${tenantId}/contract/landlord` try { const tenantDetails = await getTenantDetails(tenantId) @@ -28,28 +30,17 @@ export default async function LandlordContract({ ) } - if (tenantDetails.name && parseInt(tenantDetails.name) > 0) { - return ( - - - - - Du mangler følgende - - Placeholder - - - - ) - } + const hasContract = + tenantDetails.contracts && tenantDetails.contracts.length > 0 return ( - + {hasContract ? ( + + ) : ( + + )} ) } catch (error) { diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/layout.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/layout.tsx similarity index 81% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/layout.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/layout.tsx index b2d3874..a9b58e1 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/contract2/layout.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/contract/layout.tsx @@ -47,63 +47,61 @@ export default async function DashboardLayout({ ) const isMvaCompleted = Boolean( - contract && - contract.vatTerms !== null && - contract.businessCategory !== null, + contract?.vatTerms && contract.businessCategory, ) const sidebarNavItems: SidebarNavItem[] = [ { title: "Eiendom", - href: `/tenant/${params.id}/contract2/building`, + href: `/tenant/${params.id}/contract/building`, icon: "home", completed: true, // Always true as per your initial setup }, { title: "Utleier", - href: `/tenant/${params.id}/contract2/landlord`, + href: `/tenant/${params.id}/contract/landlord`, icon: "building", completed: isLandlordCompleted, }, { title: "Leietaker", - href: `/tenant/${params.id}/contract2/tenant`, + href: `/tenant/${params.id}/contract/tenant`, icon: "user", completed: isTenantCompleted, }, { title: "Tidsrom", - href: `/tenant/${params.id}/contract2/time`, + href: `/tenant/${params.id}/contract/time`, icon: "calendarClock", completed: isTimeCompleted, }, { title: "Leieinntekter", - href: `/tenant/${params.id}/contract2/terms`, + href: `/tenant/${params.id}/contract/terms`, icon: "piechart", completed: isTermsCompleted, }, { title: "KPI", - href: `/tenant/${params.id}/contract2/kpi`, + href: `/tenant/${params.id}/contract/kpi`, icon: "percent", completed: isKpiCompleted, }, { title: "Mva", - href: `/tenant/${params.id}/contract2/mva`, + href: `/tenant/${params.id}/contract/mva`, icon: "coins", completed: isMvaCompleted, }, { title: "Editor", - href: `/tenant/${params.id}/contract2/editor`, + href: `/tenant/${params.id}/contract/editor`, icon: "page", - completed: isMvaCompleted, + completed: false, // Changed to always be false initially }, { title: "Sammendrag", - href: `/tenant/${params.id}/contract2/summary`, + href: `/tenant/${params.id}/contract/summary`, icon: "filetext", completed: false, // Assuming summary is never initially completed }, diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/mva/_components/MvaDetailsForm.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/mva/_components/MvaDetailsForm.tsx similarity index 92% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/mva/_components/MvaDetailsForm.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/mva/_components/MvaDetailsForm.tsx index aa3e282..ec1dbcb 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/contract2/mva/_components/MvaDetailsForm.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/contract/mva/_components/MvaDetailsForm.tsx @@ -1,6 +1,6 @@ "use client" -import { useState } from "react" +import { useEffect, useState } from "react" import { updateContract } from "@/actions/update-contract" import { zodResolver } from "@hookform/resolvers/zod" import { useForm } from "react-hook-form" @@ -51,6 +51,13 @@ export function MvaDetailsForm({ tenantDetails }) { }, }) + useEffect(() => { + form.reset({ + vatTerms: tenantDetails.contracts[0]?.vatTerms || "None", + businessCategory: tenantDetails.contracts[0]?.businessCategory || "", + }) + }, [tenantDetails, form]) + const onSubmit = async (data) => { setIsLoading(true) @@ -76,7 +83,7 @@ export function MvaDetailsForm({ tenantDetails }) { return ( - VAT and Business Category + MVA og forretningskategori Oppdater moms og forretningskategori for leietakeren. diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/mva/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/mva/page.tsx similarity index 58% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/mva/page.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/mva/page.tsx index 953ab47..41ce150 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/contract2/mva/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/contract/mva/page.tsx @@ -1,11 +1,14 @@ import React from "react" +import Link from "next/link" import { getTenantDetails } from "@/actions/get-tenant-details" +import { Button } from "@dingify/ui/components/button" import { Card } from "@dingify/ui/components/card" import { DashboardHeader } from "@/components/dashboard/header" import { DashboardShell } from "@/components/dashboard/shell" import { EmptyPlaceholder } from "@/components/shared/empty-placeholder" +import { ContractCheck } from "@/components/tenant/ContractCheck" import { MvaDetailsForm } from "./_components/MvaDetailsForm" @@ -27,31 +30,20 @@ export default async function termsContractPage({ ) } - if (tenantDetails.name && parseInt(tenantDetails.name) > 0) { - return ( - - - - - Du mangler følgende - - Placeholder - - - - ) - } + const hasContract = + tenantDetails.contracts && tenantDetails.contracts.length > 0 return ( - + {hasContract ? ( + + ) : ( + + )} ) } catch (error) { diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/page.tsx index 870b7c9..b669199 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/contract/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/contract/page.tsx @@ -1,9 +1,11 @@ -import React, { useState } from "react" +import React from "react" import { getTenantDetails } from "@/actions/get-tenant-details" import { DashboardHeader } from "@/components/dashboard/header" import { DashboardShell } from "@/components/dashboard/shell" import { generateContractContent } from "@/components/editor/contractTemplate" +import Editor from "@/components/editor/editor" +import { initialContent } from "@/components/editor/initialContent" import TenantEditor from "@/components/editor/TenantEditor" import { EmptyPlaceholder } from "@/components/shared/empty-placeholder" @@ -13,15 +15,7 @@ export default async function Home({ params }: { params: { id: string } }) { try { const tenantDetails = await getTenantDetails(tenantId) - const missingFields: string[] = [] - if (!tenantDetails?.contacts || tenantDetails.contacts.length === 0) { - missingFields.push("Du må legge til kontaktperson") - } - if (!tenantDetails?.contracts || tenantDetails.contracts.length === 0) { - missingFields.push("Du må legge til kontrakt") - } - - if (missingFields.length > 0) { + if (tenantDetails?.name && parseInt(tenantDetails.name) > 0) { return ( Du mangler følgende -
      - {missingFields.map((field, index) => ( -
    • - {field} -
    • - ))} -
    + Placeholder
    ) } - const contractContent = generateContractContent(tenantDetails) - return ( - - {/* */} ) } catch (error) { diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/summary/_components/SummaryDetailsForm.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/summary/_components/SummaryDetailsForm.tsx similarity index 100% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/summary/_components/SummaryDetailsForm.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/summary/_components/SummaryDetailsForm.tsx diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract/summary/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/summary/page.tsx new file mode 100644 index 0000000..b9021f6 --- /dev/null +++ b/apps/www/src/app/(tenant)/tenant/[id]/contract/summary/page.tsx @@ -0,0 +1,43 @@ +import React from "react" +import { getTenantDetails } from "@/actions/get-tenant-details" + +import { Card } from "@dingify/ui/components/card" + +import { DashboardHeader } from "@/components/dashboard/header" +import { DashboardShell } from "@/components/dashboard/shell" +import { EmptyPlaceholder } from "@/components/shared/empty-placeholder" +import { ContractCheck } from "@/components/tenant/ContractCheck" + +import { SummaryDetailsForm } from "./_components/SummaryDetailsForm" + +export default async function SummaryPage({ + params, +}: { + params: { id: string } +}) { + const tenantId = params.id + + try { + const tenantDetails = await getTenantDetails(tenantId) + + const hasContract = + tenantDetails?.contracts && tenantDetails?.contracts.length > 0 + + return ( + + + {hasContract ? ( + + ) : ( + + )} + + ) + } catch (error) { + return ( + + + + ) + } +} diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/tenant/_components/TenantDetailsForm.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/tenant/_components/TenantDetailsForm.tsx similarity index 100% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/tenant/_components/TenantDetailsForm.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/tenant/_components/TenantDetailsForm.tsx diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/tenant/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/tenant/page.tsx similarity index 58% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/tenant/page.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/tenant/page.tsx index 36f6544..adb4e82 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/contract2/tenant/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/contract/tenant/page.tsx @@ -1,11 +1,14 @@ import React from "react" +import Link from "next/link" import { getTenantDetails } from "@/actions/get-tenant-details" +import { Button } from "@dingify/ui/components/button" import { Card } from "@dingify/ui/components/card" import { DashboardHeader } from "@/components/dashboard/header" import { DashboardShell } from "@/components/dashboard/shell" import { EmptyPlaceholder } from "@/components/shared/empty-placeholder" +import { ContractCheck } from "@/components/tenant/ContractCheck" import { TenantDetailsForm } from "./_components/TenantDetailsForm" @@ -23,31 +26,20 @@ export default async function Home({ params }: { params: { id: string } }) { ) } - if (tenantDetails.name && parseInt(tenantDetails.name) > 0) { - return ( - - - - - Du mangler følgende - - Placeholder - - - - ) - } + const hasContract = + tenantDetails.contracts && tenantDetails.contracts.length > 0 return ( - + {hasContract ? ( + + ) : ( + + )} ) } catch (error) { diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/terms/_components/TermsDetailsForm.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/terms/_components/TermsDetailsForm.tsx similarity index 100% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/terms/_components/TermsDetailsForm.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/terms/_components/TermsDetailsForm.tsx diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/terms/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/terms/page.tsx similarity index 58% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/terms/page.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/terms/page.tsx index f95d462..5157cd8 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/contract2/terms/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/contract/terms/page.tsx @@ -1,11 +1,14 @@ import React from "react" +import Link from "next/link" import { getTenantDetails } from "@/actions/get-tenant-details" +import { Button } from "@dingify/ui/components/button" import { Card } from "@dingify/ui/components/card" import { DashboardHeader } from "@/components/dashboard/header" import { DashboardShell } from "@/components/dashboard/shell" import { EmptyPlaceholder } from "@/components/shared/empty-placeholder" +import { ContractCheck } from "@/components/tenant/ContractCheck" import { TermsDetailsForm } from "./_components/TermsDetailsForm" @@ -27,31 +30,20 @@ export default async function termsContractPage({ ) } - if (tenantDetails.name && parseInt(tenantDetails.name) > 0) { - return ( - - - - - Du mangler følgende - - Placeholder - - - - ) - } + const hasContract = + tenantDetails.contracts && tenantDetails.contracts.length > 0 return ( - + {hasContract ? ( + + ) : ( + + )} ) } catch (error) { diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/time/_components/TimeDetailsForm.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/time/_components/TimeDetailsForm.tsx similarity index 100% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/time/_components/TimeDetailsForm.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/time/_components/TimeDetailsForm.tsx diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/time/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract/time/page.tsx similarity index 60% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/time/page.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contract/time/page.tsx index ea92a36..a846389 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/contract2/time/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/contract/time/page.tsx @@ -1,11 +1,14 @@ import React from "react" +import Link from "next/link" import { getTenantDetails } from "@/actions/get-tenant-details" +import { Button } from "@dingify/ui/components/button" import { Card } from "@dingify/ui/components/card" import { DashboardHeader } from "@/components/dashboard/header" import { DashboardShell } from "@/components/dashboard/shell" import { EmptyPlaceholder } from "@/components/shared/empty-placeholder" +import { ContractCheck } from "@/components/tenant/ContractCheck" import { TimeDetailsForm } from "./_components/TimeDetailsForm" @@ -28,31 +31,20 @@ export default async function TimeContract({ ) } - if (tenantDetails.name && parseInt(tenantDetails.name) > 0) { - return ( - - - - - Du mangler følgende - - Placeholder - - - - ) - } + const hasContract = + tenantDetails.contracts && tenantDetails.contracts.length > 0 return ( - + {hasContract ? ( + + ) : ( + + )} ) } catch (error) { diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/summary/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contract2/summary/page.tsx deleted file mode 100644 index 68caf86..0000000 --- a/apps/www/src/app/(tenant)/tenant/[id]/contract2/summary/page.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import React from "react" -import { getTenantDetails } from "@/actions/get-tenant-details" - -import { Card } from "@dingify/ui/components/card" - -import { DashboardHeader } from "@/components/dashboard/header" -import { DashboardShell } from "@/components/dashboard/shell" -import { EmptyPlaceholder } from "@/components/shared/empty-placeholder" - -import { SummaryDetailsForm } from "./_components/SummaryDetailsForm" - -export default async function SummaryPage({ - params, -}: { - params: { id: string } -}) { - const tenantId = params.id - - try { - const tenantDetails = await getTenantDetails(tenantId) - - if (!tenantDetails) { - return ( - - - - ) - } - - if (tenantDetails.name && parseInt(tenantDetails.name) > 0) { - return ( - - - - - Du mangler følgende - - Placeholder - - - - ) - } - - return ( - - - - - ) - } catch (error) { - return ( - - - - ) - } -} diff --git a/apps/www/src/app/(tenant)/tenant/[id]/contract2/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/contractxxx/page.tsx similarity index 65% rename from apps/www/src/app/(tenant)/tenant/[id]/contract2/page.tsx rename to apps/www/src/app/(tenant)/tenant/[id]/contractxxx/page.tsx index b669199..870b7c9 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/contract2/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/contractxxx/page.tsx @@ -1,11 +1,9 @@ -import React from "react" +import React, { useState } from "react" import { getTenantDetails } from "@/actions/get-tenant-details" import { DashboardHeader } from "@/components/dashboard/header" import { DashboardShell } from "@/components/dashboard/shell" import { generateContractContent } from "@/components/editor/contractTemplate" -import Editor from "@/components/editor/editor" -import { initialContent } from "@/components/editor/initialContent" import TenantEditor from "@/components/editor/TenantEditor" import { EmptyPlaceholder } from "@/components/shared/empty-placeholder" @@ -15,7 +13,15 @@ export default async function Home({ params }: { params: { id: string } }) { try { const tenantDetails = await getTenantDetails(tenantId) - if (tenantDetails?.name && parseInt(tenantDetails.name) > 0) { + const missingFields: string[] = [] + if (!tenantDetails?.contacts || tenantDetails.contacts.length === 0) { + missingFields.push("Du må legge til kontaktperson") + } + if (!tenantDetails?.contracts || tenantDetails.contracts.length === 0) { + missingFields.push("Du må legge til kontrakt") + } + + if (missingFields.length > 0) { return ( Du mangler følgende - Placeholder +
      + {missingFields.map((field, index) => ( +
    • + {field} +
    • + ))} +
    ) } + const contractContent = generateContractContent(tenantDetails) + return ( + + {/* */} ) } catch (error) { diff --git a/apps/www/src/app/(tenant)/tenant/[id]/finance/page.tsx b/apps/www/src/app/(tenant)/tenant/[id]/finance/page.tsx index fb94138..61bdd5a 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/finance/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/finance/page.tsx @@ -40,7 +40,7 @@ export default async function EconomySettings({ heading="Økonomi" text="Endre økonomiske innstillinger for leietakeren." > - Legg til kontrakt - + */} {!contractDetails || contractDetails.length === 0 ? ( diff --git a/apps/www/src/app/(tenant)/tenant/[id]/layout.tsx b/apps/www/src/app/(tenant)/tenant/[id]/layout.tsx index b31be84..52da7f0 100644 --- a/apps/www/src/app/(tenant)/tenant/[id]/layout.tsx +++ b/apps/www/src/app/(tenant)/tenant/[id]/layout.tsx @@ -42,12 +42,7 @@ export default async function DashboardLayout({ }, { title: "Kontrakt", - href: `/tenant/${params.id}/contract`, - icon: "filetext", - }, - { - title: "Kontrakt v2", - href: `/tenant/${params.id}/contract2/building`, + href: `/tenant/${params.id}/contract/building`, icon: "filetext", }, { diff --git a/apps/www/src/app/(tenant)/tenant/page.tsx b/apps/www/src/app/(tenant)/tenant/page.tsx index 690d6bb..e1b9acd 100644 --- a/apps/www/src/app/(tenant)/tenant/page.tsx +++ b/apps/www/src/app/(tenant)/tenant/page.tsx @@ -75,7 +75,7 @@ export default async function DashboardPage() { - + {/* */}
    {tenants.length === 0 ? ( diff --git a/apps/www/src/components/buttons/EditContractDetails.tsx b/apps/www/src/components/buttons/EditContractDetails.tsx index 50f23bc..d81030f 100644 --- a/apps/www/src/components/buttons/EditContractDetails.tsx +++ b/apps/www/src/components/buttons/EditContractDetails.tsx @@ -96,12 +96,14 @@ export function EditContractSheet({ const form = useForm({ resolver: zodResolver(ContractSchema), defaultValues: { - ...initialValues, - startDate: formatDateString(initialValues.startDate), - endDate: formatDateString(initialValues.endDate), - negotiationDate: formatDateString(initialValues.negotiationDate), - baseRent: initialValues.baseRent?.toString() ?? "", - indexValue: initialValues.indexValue?.toString() ?? "", + contractType: initialValues.contractType || undefined, + startDate: formatDateString(initialValues.startDate) || undefined, + endDate: formatDateString(initialValues.endDate) || undefined, + negotiationDate: + formatDateString(initialValues.negotiationDate) || undefined, + baseRent: initialValues.baseRent?.toString() || undefined, + indexationType: initialValues.indexationType || undefined, + indexValue: initialValues.indexValue?.toString() || undefined, }, }) diff --git a/apps/www/src/components/table/tenant/columns.tsx b/apps/www/src/components/table/tenant/columns.tsx index 228e76d..2b405a2 100644 --- a/apps/www/src/components/table/tenant/columns.tsx +++ b/apps/www/src/components/table/tenant/columns.tsx @@ -64,14 +64,14 @@ export const TenantColumns: ColumnDef[] = [ }, { accessorKey: "isRenting", - header: "Renting Status", + header: "Leiestatus", cell: ({ row }) => ( -
    {row.getValue("isRenting") ? "Renting" : "Not Renting"}
    +
    {row.getValue("isRenting") ? "Leier" : "Leier ikke"}
    ), }, { accessorKey: "currentRent", - header: "Current Rent", + header: "Nåværende leie", cell: ({ row }) => { const amount = row.getValue("currentRent") return amount ? `${amount.toLocaleString()} NOK` : "N/A" @@ -79,7 +79,7 @@ export const TenantColumns: ColumnDef[] = [ }, { accessorKey: "contractStartDate", - header: "Contract Start", + header: "Kontraktstart", cell: ({ row }) => { const date = row.getValue("contractStartDate") return date ? format(new Date(date), "dd.MM.yyyy") : "N/A" @@ -87,7 +87,7 @@ export const TenantColumns: ColumnDef[] = [ }, { accessorKey: "contractEndDate", - header: "Contract End", + header: "Kontraktslutt", cell: ({ row }) => { const date = row.getValue("contractEndDate") return date ? format(new Date(date), "dd.MM.yyyy") : "N/A" @@ -113,15 +113,15 @@ export const TenantColumns: ColumnDef[] = [ - Actions + Handlinger e.preventDefault()}> - Edit + Rediger diff --git a/apps/www/src/components/tenant/ContractCheck.tsx b/apps/www/src/components/tenant/ContractCheck.tsx new file mode 100644 index 0000000..146a304 --- /dev/null +++ b/apps/www/src/components/tenant/ContractCheck.tsx @@ -0,0 +1,86 @@ +"use client" + +import React from "react" +import { useRouter } from "next/navigation" +import { createContract } from "@/actions/create-contract" +import { toast } from "sonner" + +import { Button } from "@dingify/ui/components/button" + +import { EmptyPlaceholder } from "@/components/shared/empty-placeholder" + +interface ContractCheckProps { + tenantDetails: any // Update this type to match your tenant details structure + onContractCreated?: () => void +} + +export function ContractCheck({ + tenantDetails, + onContractCreated, +}: ContractCheckProps) { + const router = useRouter() + + const handleCreateContract = async () => { + try { + const contractData = { + tenantId: tenantDetails.id, + workspaceId: tenantDetails.workspaceId, // Assuming this is available in tenantDetails + propertyId: tenantDetails.property?.id?.toString() || "", + buildingId: tenantDetails.building?.id?.toString() || "", + floors: tenantDetails.floor + ? { connect: { id: tenantDetails.floor.id } } + : undefined, + officeSpaces: tenantDetails.officeSpace + ? { connect: { id: tenantDetails.officeSpace.id } } + : undefined, + contactId: tenantDetails.contacts[0]?.id || 0, + // Add other fields as needed, with default values + landlordOrgnr: null, + landlordName: "", + contractType: null, + contactName: "", + contactEmail: "", + contactPhone: "", + startDate: null, + endDate: null, + negotiationDate: null, + isRenewable: false, + renewablePeriod: null, + indexationType: null, + indexValue: null, + indexationDate: null, + baseRent: null, + rentPeriod: null, + vatTerms: "", + businessCategory: "", + collateral: null, + } + + const result = await createContract(contractData) + if (result.success) { + toast.success("Ny kontrakt opprettet") + if (onContractCreated) { + onContractCreated() + } + router.refresh() + } else { + throw new Error(result.error || "Failed to create contract.") + } + } catch (error) { + toast.error(error.message) + console.error(error) + } + } + + return ( + + + Ingen kontrakt funnet + + Du har ikke opprettet noen kontrakt ennå. Klikk på knappen nedenfor for + å opprette en ny kontrakt. + + + + ) +} diff --git a/apps/www/src/components/users/UserNavTop.tsx b/apps/www/src/components/users/UserNavTop.tsx index b59d67f..969e9ac 100644 --- a/apps/www/src/components/users/UserNavTop.tsx +++ b/apps/www/src/components/users/UserNavTop.tsx @@ -3,7 +3,7 @@ import React, { useState } from "react" import { useRouter } from "next/navigation" import { createSmsTenant } from "@/actions/create-sms-tenant" -import { File, ListFilter, PlusCircle } from "lucide-react" +import { ChevronDown, File, MessageSquare, PlusCircle } from "lucide-react" import { toast } from "sonner" import { Button } from "@dingify/ui/components/button" @@ -42,11 +42,14 @@ export function UserNavTop({ tenantDetails }) { router.push(`/tenant/${tenantDetails.id}/contract/`) } - const handleSendSMSClick = () => { + const handleSMSClick = () => { if (tenantDetails.contacts && tenantDetails.contacts.length > 0) { const contact = tenantDetails.contacts[0] setContactName(contact.name || "") - setPhone(contact.phone || "") + setPhone(contact.phone || "Ingen telefonnummer registrert") + } else { + setContactName("Ingen kontaktperson registrert") + setPhone("Ingen telefonnummer registrert") } setIsDialogOpen(true) } @@ -71,29 +74,23 @@ export function UserNavTop({ tenantDetails }) { return (
    - - - - - - Filter by - - Active - Draft - Archived - - + Lag ny - - Send SMS - Kontrakt @@ -162,7 +157,11 @@ export function UserNavTop({ tenantDetails }) {
    -