From af3db00837c806a3c95873763c7a89e44e48f51a Mon Sep 17 00:00:00 2001 From: Lewis Carhart Date: Thu, 3 Apr 2025 20:16:44 -0400 Subject: [PATCH] feat: add policy layout components and enhance policy details page - Introduced new layout components for policy overview and individual policy pages, improving structure and navigation. - Updated PolicyDetails page to include a PolicyPageEditor for editing policy content. - Removed deprecated PolicyEditor component to streamline the codebase. - Implemented responsive design with Tailwind CSS for better user experience. --- .../policies/{ => (overview)}/layout.tsx | 0 .../editor/components/PolicyDetails.tsx | 48 +++---- .../policies/[policyId]/editor/page.tsx | 65 --------- .../[orgId]/policies/[policyId]/layout.tsx | 31 ++++ .../[orgId]/policies/[policyId]/page.tsx | 133 +++++++++--------- .../[orgId]/policies/all/layout.tsx | 31 ++++ 6 files changed, 156 insertions(+), 152 deletions(-) rename apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/{ => (overview)}/layout.tsx (100%) delete mode 100644 apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/editor/page.tsx create mode 100644 apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/layout.tsx create mode 100644 apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/layout.tsx diff --git a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/layout.tsx b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/(overview)/layout.tsx similarity index 100% rename from apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/layout.tsx rename to apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/(overview)/layout.tsx diff --git a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/editor/components/PolicyDetails.tsx b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/editor/components/PolicyDetails.tsx index 1feb8f11fa..2cfd35b95a 100644 --- a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/editor/components/PolicyDetails.tsx +++ b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/editor/components/PolicyDetails.tsx @@ -5,33 +5,33 @@ import type { JSONContent } from "@tiptap/react"; import "@comp/ui/editor.css"; import { updatePolicy } from "../actions/update-policy"; interface PolicyDetailsProps { - policyId: string; - policyContent: JSONContent | JSONContent[]; + policyId: string; + policyContent: JSONContent | JSONContent[]; } -export function PolicyDetails({ policyId, policyContent }: PolicyDetailsProps) { - const formattedContent = Array.isArray(policyContent) - ? policyContent - : typeof policyContent === "object" && policyContent !== null - ? [policyContent as JSONContent] - : []; +export function PolicyPageEditor({ policyId, policyContent }: PolicyDetailsProps) { + const formattedContent = Array.isArray(policyContent) + ? policyContent + : typeof policyContent === "object" && policyContent !== null + ? [policyContent as JSONContent] + : []; - const handleSavePolicy = async ( - policyContent: JSONContent[], - ): Promise => { - if (!policyId) return; + const handleSavePolicy = async ( + policyContent: JSONContent[], + ): Promise => { + if (!policyId) return; - try { - await updatePolicy({ policyId, content: policyContent }); - } catch (error) { - console.error("Error saving policy:", error); - throw error; - } - }; + try { + await updatePolicy({ policyId, content: policyContent }); + } catch (error) { + console.error("Error saving policy:", error); + throw error; + } + }; - return ( -
- -
- ); + return ( +
+ +
+ ); } diff --git a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/editor/page.tsx b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/editor/page.tsx deleted file mode 100644 index 3c81942a1d..0000000000 --- a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/editor/page.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { getI18n } from "@/locales/server"; -import type { Metadata } from "next"; -import { setStaticParamsLocale } from "next-international/server"; -import { PolicyDetails } from "./components/PolicyDetails"; -import { auth } from "@comp/auth"; -import { db } from "@comp/db"; -import { headers } from "next/headers"; -import { cache } from "react"; -import { redirect } from "next/navigation"; -import { JSONContent } from "novel"; - -export default async function PolicyEditor({ - params, -}: { - params: Promise<{ locale: string; policyId: string }>; -}) { - const { locale, policyId } = await params; - setStaticParamsLocale(locale); - - const policy = await getPolicy(policyId); - - return ( - - ); -} - -export async function generateMetadata({ - params, -}: { - params: Promise<{ locale: string; policyId: string }>; -}): Promise { - const { locale } = await params; - - setStaticParamsLocale(locale); - const t = await getI18n(); - - return { - title: t("policies.dashboard.sub_pages.edit_policy"), - }; -} - -const getPolicy = cache(async (policyId: string) => { - const session = await auth.api.getSession({ - headers: await headers(), - }); - - const organizationId = session?.session.activeOrganizationId; - - if (!organizationId) { - return null; - } - - const policy = await db.policy.findUnique({ - where: { id: policyId, organizationId }, - }); - - if (!policy) { - return redirect("/"); - } - - return policy; -}); diff --git a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/layout.tsx b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/layout.tsx new file mode 100644 index 0000000000..aa967759a0 --- /dev/null +++ b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/layout.tsx @@ -0,0 +1,31 @@ +import { getI18n } from "@/locales/server"; +import { SecondaryMenu } from "@comp/ui/secondary-menu"; + +interface LayoutProps { + children: React.ReactNode; + params: Promise<{ policyId: string; orgId: string }>; +} + +export default async function Layout({ children, params }: LayoutProps) { + const t = await getI18n(); + const { orgId, policyId } = await params; + + return ( +
+ +
{children}
+
+ ); +} diff --git a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/page.tsx b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/page.tsx index a286468011..c4c71f16d7 100644 --- a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/page.tsx +++ b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/[policyId]/page.tsx @@ -6,89 +6,96 @@ import { db } from "@comp/db"; import type { Metadata } from "next"; import { setStaticParamsLocale } from "next-international/server"; import { headers } from "next/headers"; +import { JSONContent } from "novel"; import { cache } from "react"; +import { PolicyPageEditor } from "./editor/components/PolicyDetails"; + export default async function PolicyDetails({ - params, + params, }: { - params: Promise<{ locale: string; policyId: string; orgId: string }>; + params: Promise<{ locale: string; policyId: string; orgId: string }>; }) { - const { locale, policyId, orgId } = await params; - - setStaticParamsLocale(locale); - const policy = await getPolicy(policyId); - const assignees = await getAssignees(); - - return ( - - - - ); + const { locale, policyId, orgId } = await params; + + setStaticParamsLocale(locale); + const policy = await getPolicy(policyId); + const assignees = await getAssignees(); + + return ( + + + + + ); } export async function generateMetadata({ - params, + params, }: { - params: Promise<{ locale: string; policyId: string }>; + params: Promise<{ locale: string; policyId: string }>; }): Promise { - const { locale } = await params; + const { locale } = await params; - setStaticParamsLocale(locale); - const t = await getI18n(); + setStaticParamsLocale(locale); + const t = await getI18n(); - return { - title: t("policies.overview.title"), - }; + return { + title: t("policies.overview.title"), + }; } const getPolicy = cache(async (policyId: string) => { - const session = await auth.api.getSession({ - headers: await headers(), - }); + const session = await auth.api.getSession({ + headers: await headers(), + }); - const organizationId = session?.session.activeOrganizationId; + const organizationId = session?.session.activeOrganizationId; - if (!organizationId) { - return null; - } + if (!organizationId) { + return null; + } - const policy = await db.policy.findUnique({ - where: { id: policyId, organizationId }, - }); + const policy = await db.policy.findUnique({ + where: { id: policyId, organizationId }, + }); - if (!policy) { - return null; - } + if (!policy) { + return null; + } - return policy; + return policy; }); const getAssignees = cache(async () => { - const session = await auth.api.getSession({ - headers: await headers(), - }); - - const organizationId = session?.session.activeOrganizationId; - - if (!organizationId) { - return []; - } - - const assignees = await db.member.findMany({ - where: { - organizationId, - role: { - notIn: ["employee"], - }, - }, - include: { - user: true, - }, - }); - - return assignees; + const session = await auth.api.getSession({ + headers: await headers(), + }); + + const organizationId = session?.session.activeOrganizationId; + + if (!organizationId) { + return []; + } + + const assignees = await db.member.findMany({ + where: { + organizationId, + role: { + notIn: ["employee"], + }, + }, + include: { + user: true, + }, + }); + + return assignees; }); diff --git a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/layout.tsx b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/layout.tsx new file mode 100644 index 0000000000..8e49ebb567 --- /dev/null +++ b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/layout.tsx @@ -0,0 +1,31 @@ +import { getI18n } from "@/locales/server"; +import { SecondaryMenu } from "@comp/ui/secondary-menu"; + +interface LayoutProps { + children: React.ReactNode; + params: Promise<{ policyId: string; orgId: string }>; +} + +export default async function Layout({ children, params }: LayoutProps) { + const t = await getI18n(); + const { orgId } = await params; + + return ( +
+ +
{children}
+
+ ); +}