diff --git a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/actions/updateWizard.ts b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/actions/updateWizard.ts index 2cb4b95a65..b193ac11fc 100644 --- a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/actions/updateWizard.ts +++ b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/actions/updateWizard.ts @@ -53,31 +53,26 @@ export const updateWizard = async ({ where: { organizationId: orgId }, }); - if (!onboarding) { - await db.onboarding.create({ - data: { - organizationId: orgId, - [dbColumn]: { - version: parsed.version || companyDetailsLatestVersion, - isCompleted: parsed.isCompleted, - data: parsed.data, - }, + await db.onboarding.upsert({ + where: { + organizationId: orgId, + }, + create: { + organizationId: orgId, + [dbColumn]: { + version: parsed.version || companyDetailsLatestVersion, + isCompleted: parsed.isCompleted, + data: parsed.data, }, - }); - } else { - await db.onboarding.update({ - where: { - organizationId: orgId, + }, + update: { + [dbColumn]: { + version: parsed.version || companyDetailsLatestVersion, + isCompleted: parsed.isCompleted, + data: parsed.data, }, - data: { - [dbColumn]: { - version: parsed.version || companyDetailsLatestVersion, - isCompleted: parsed.isCompleted, - data: parsed.data, - }, - }, - }); - } + }, + }); revalidatePath(`/${orgId}/implementation/wizard/${wizardId}`); diff --git a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/components/CompanyDetailsWizardForm.tsx b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/components/CompanyDetailsWizardForm.tsx index bfd61320db..ee230c0fa2 100644 --- a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/components/CompanyDetailsWizardForm.tsx +++ b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/components/CompanyDetailsWizardForm.tsx @@ -29,14 +29,7 @@ import { SelectValue, } from "@comp/ui/select"; import { useParams, useRouter } from "next/navigation"; -import { - Breadcrumb, - BreadcrumbItem, - BreadcrumbLink, - BreadcrumbPage, - BreadcrumbSeparator, -} from "@comp/ui/breadcrumb"; -import PageWithBreadcrumb from "@/components/pages/PageWithBreadcrumb"; +import { Card, CardContent, CardHeader, CardTitle } from "@comp/ui/card"; const steps = [ "Company identity", @@ -220,14 +213,14 @@ export const CompanyDetailsWizardForm = ({ return (
{errors.companyWebsite && ( @@ -274,9 +267,9 @@ export const CompanyDetailsWizardForm = ({ ); return found ? { - value: found.value, - label: found.label, - } + value: found.value, + label: found.label, + } : { value: v, label: v }; })} placeholder="Select or add one..." @@ -592,16 +585,24 @@ export const CompanyDetailsWizardForm = ({ } }} > - - 0} - /> + + + + + + + + 0} + /> + + ); diff --git a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/components/WizardQuestion.tsx b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/components/WizardQuestion.tsx index 53f42546cb..6b9fa2c23d 100644 --- a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/components/WizardQuestion.tsx +++ b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/components/WizardQuestion.tsx @@ -35,8 +35,8 @@ export function WizardQuestion({ )}
-
- +
+ Step {step + 1} / {totalSteps}
diff --git a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/components/WizardStepper.tsx b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/components/WizardStepper.tsx index fc8e09afba..6762b96c2d 100644 --- a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/components/WizardStepper.tsx +++ b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/implementation/wizard/[wizardId]/components/WizardStepper.tsx @@ -7,8 +7,8 @@ interface WizardStepperProps { export function WizardStepper({ steps, currentStep }: WizardStepperProps) { return ( -
-
{steps[currentStep]}
-
+
+
{steps[currentStep]}
+
); } diff --git a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/settings/trust-portal/components/TrustPortalSwitch.tsx b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/settings/trust-portal/components/TrustPortalSwitch.tsx index ccf372cf7d..a37eb5fca9 100644 --- a/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/settings/trust-portal/components/TrustPortalSwitch.tsx +++ b/apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/settings/trust-portal/components/TrustPortalSwitch.tsx @@ -1,7 +1,7 @@ "use client" import { useI18n } from "@/locales/client" -import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@comp/ui/card" +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@comp/ui/card" import { Form, FormControl, FormField, FormItem, FormLabel } from "@comp/ui/form" import { Switch } from "@comp/ui/switch" import { zodResolver } from "@hookform/resolvers/zod" @@ -11,9 +11,8 @@ import { toast } from "sonner" import { z } from "zod" import { trustPortalSwitchAction } from "../actions/trust-portal-switch" import Link from "next/link" -import { ExternalLink, Loader2 } from "lucide-react" +import { ExternalLink } from "lucide-react" import { Input } from "@comp/ui/input" -import { Button } from "@comp/ui/button" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@comp/ui/select" import { updateTrustPortalFrameworks } from "../actions/update-trust-portal-frameworks" import { SOC2, ISO27001, GDPR } from "./logos" @@ -96,14 +95,12 @@ export function TrustPortalSwitch({ const portalUrl = domainVerified ? `https://${domain}` : `https://trust.inc/${slug}` - // --- Auto-save helpers --- const lastSaved = useRef<{ [key: string]: string | boolean }>({ contactEmail: contactEmail ?? "", friendlyUrl: friendlyUrl ?? "", enabled: enabled, }) - // Save handler const autoSave = useCallback( async (field: string, value: any) => { const current = form.getValues() @@ -116,11 +113,9 @@ export function TrustPortalSwitch({ [form, onSubmit] ) - // --- Field Handlers --- - // Contact Email const [contactEmailValue, setContactEmailValue] = useState(form.getValues("contactEmail") || "") const debouncedContactEmail = useDebounce(contactEmailValue, 500) - // Debounced auto-save + useEffect(() => { if ( debouncedContactEmail !== undefined && @@ -129,9 +124,8 @@ export function TrustPortalSwitch({ form.setValue("contactEmail", debouncedContactEmail) autoSave("contactEmail", debouncedContactEmail) } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [debouncedContactEmail]) - // On blur immediate save + const handleContactEmailBlur = useCallback( (e: React.FocusEvent) => { const value = e.target.value @@ -141,11 +135,10 @@ export function TrustPortalSwitch({ [form, autoSave] ) - // Friendly URL const [friendlyUrlValue, setFriendlyUrlValue] = useState(form.getValues("friendlyUrl") || "") const debouncedFriendlyUrl = useDebounce(friendlyUrlValue, 500) const [friendlyUrlStatus, setFriendlyUrlStatus] = useState<"idle" | "checking" | "available" | "unavailable">("idle") - // Check availability on debounce + useEffect(() => { if (!debouncedFriendlyUrl || debouncedFriendlyUrl === (friendlyUrl ?? "")) { setFriendlyUrlStatus("idle") @@ -153,13 +146,12 @@ export function TrustPortalSwitch({ } setFriendlyUrlStatus("checking") checkFriendlyUrl.execute({ friendlyUrl: debouncedFriendlyUrl, orgId }) - // eslint-disable-next-line react-hooks/exhaustive-deps }, [debouncedFriendlyUrl, orgId, friendlyUrl]) useEffect(() => { if (checkFriendlyUrl.status === "executing") return if (checkFriendlyUrl.result?.data?.isAvailable === true) { setFriendlyUrlStatus("available") - // Auto-save if available and changed + if (debouncedFriendlyUrl !== lastSaved.current.friendlyUrl) { form.setValue("friendlyUrl", debouncedFriendlyUrl) autoSave("friendlyUrl", debouncedFriendlyUrl) @@ -167,9 +159,8 @@ export function TrustPortalSwitch({ } else if (checkFriendlyUrl.result?.data?.isAvailable === false) { setFriendlyUrlStatus("unavailable") } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [checkFriendlyUrl.status, checkFriendlyUrl.result]) - // On blur immediate save if available + const handleFriendlyUrlBlur = useCallback( (e: React.FocusEvent) => { const value = e.target.value @@ -181,7 +172,6 @@ export function TrustPortalSwitch({ [form, autoSave, friendlyUrlStatus] ) - // Enabled switch immediate save const handleEnabledChange = useCallback( (val: boolean) => { form.setValue("enabled", val) @@ -230,7 +220,7 @@ export function TrustPortalSwitch({ {form.watch("enabled") && (

Trust Portal Settings

-
+
{/* Compliance Frameworks Section */}
-

Compliance Frameworks

-
+

Compliance Frameworks

+

Share the frameworks your organization is compliant with or working towards.

+
{/* SOC 2 */} { @@ -339,7 +330,7 @@ export function TrustPortalSwitch({ {/* ISO 27001 */} { @@ -368,7 +359,7 @@ export function TrustPortalSwitch({ {/* GDPR */} { @@ -399,15 +390,6 @@ export function TrustPortalSwitch({
)} - - {enabled ? ( - - Click here to visit your trust portal. - - ) : ( -

Trust portal is currently disabled.

- )} -
@@ -430,31 +412,65 @@ function ComplianceFramework({ onStatusChange: (value: string) => Promise onToggle: (checked: boolean) => Promise }) { - const logo = title === "SOC 2" ? : title === "ISO 27001" ? : + const logo = title === "SOC 2" ? : title === "ISO 27001" ? : return ( -
-
-
- {logo} -

{title}

-
-
-
- {isEnabled && ( - - )} - -
-
+ <> + + +
+
{logo}
+
+ {title} + {description} +
+
+
+
+ +
+
+ {isEnabled ? ( + + ) : ( +
+ Disabled +
+ )} +
+
+ +
+
+
+ + ) } diff --git a/packages/ui/src/components/input.tsx b/packages/ui/src/components/input.tsx index 35fc1aa294..70535159f6 100644 --- a/packages/ui/src/components/input.tsx +++ b/packages/ui/src/components/input.tsx @@ -16,22 +16,9 @@ const Input = React.forwardRef( return (
- {isUrl && ( + {isPrefix && props.prefix && ( - https:// - - )} - {isPrefix && ( - ( "placeholder:text-muted-foreground file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-0", "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", - isUrl ? "pl-[80px]" : leftIcon ? "pl-[36px]" : "px-3", - !isUrl && isPrefix ? "pl-[90px]" : leftIcon ? "pl-[36px]" : "px-3", + isPrefix ? "pl-[90px]" : leftIcon ? "pl-[36px]" : "px-3", )} ref={ref} {...props} diff --git a/packages/ui/src/components/select.tsx b/packages/ui/src/components/select.tsx index fda7c5dbb3..8ef7fec4b4 100644 --- a/packages/ui/src/components/select.tsx +++ b/packages/ui/src/components/select.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import * as SelectPrimitive from "@radix-ui/react-select"; -import { Check, ChevronDown, ChevronUp } from "lucide-react"; +import { Check, ChevronDown, ChevronsUpDown, ChevronUp } from "lucide-react"; import { cn } from "../utils"; @@ -26,7 +26,7 @@ const SelectTrigger = React.forwardRef< > {children} - + )); @@ -77,7 +77,7 @@ const SelectContent = React.forwardRef< className={cn( "relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-sm border bg-popover text-popover-foreground shadow-md 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 origin-[--radix-select-content-transform-origin]", position === "popper" && - "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", + "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", className, )} position={position} @@ -88,7 +88,7 @@ const SelectContent = React.forwardRef< className={cn( "p-1", position === "popper" && - "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]", + "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]", )} > {children}