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 (
-
+
);
}
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 (
-
-
-
- {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}