SavvySolve Docs

Settings Page

Configure call preferences, integrations, notifications, and account security settings

Settings Page

The settings page allows solvers to configure their preferences and manage integrations. Located at /dashboard/settings, it provides control over call handling, notifications, payment setup, and security.

Page Sections

The settings page is organized into several cards:

  1. Call Preferences - How voice calls are handled
  2. Google Meet Integration - Video calling status
  3. Notifications - Browser and sound alerts
  4. Payment Settings - Stripe Connect status
  5. Security - Account security via Clerk
  6. Help & Support - Documentation and contact links

Call Preferences

Solvers can choose how they receive voice calls from customers.

Options

OptionDescription
In-App Calling (WebRTC)Calls handled directly in the browser using WebRTC. Requires microphone access.
Phone BridgeCalls forwarded to the solver's personal phone number. Requires phone number in profile.

Implementation

The preference is saved via the updateProfile mutation:

app/(authenticated)/dashboard/settings/page.tsx
const handleCallPreferenceChange = (value: "in_app" | "bridge") => {
  updateProfile.mutate({ callPreference: value });
};

return (
  <RadioGroup
    value={solver.callPreference}
    onValueChange={(value) =>
      handleCallPreferenceChange(value as "in_app" | "bridge")
    }
  >
    <div className="flex items-start space-x-3 rounded-lg border p-4">
      <RadioGroupItem value="in_app" id="in_app" />
      <div>
        <Label htmlFor="in_app">In-App Calling (WebRTC)</Label>
        <p className="text-sm text-muted-foreground">
          Make and receive calls directly in your browser.
        </p>
      </div>
    </div>
    <div className="flex items-start space-x-3 rounded-lg border p-4">
      <RadioGroupItem value="bridge" id="bridge" />
      <div>
        <Label htmlFor="bridge">Phone Bridge</Label>
        <p className="text-sm text-muted-foreground">
          Calls are bridged to your personal phone number.
        </p>
      </div>
    </div>
  </RadioGroup>
);

Google Meet Integration

Video calling through Google Meet is available for employed (W-2) solvers with a configured Google Workspace email.

Status States

Enabled - Shows green success banner with connected email:

{solver.employment === "employed" && solver.googleEmail ? (
  <div className="flex items-center gap-3 rounded-lg bg-green-50 p-4">
    <CheckCircle className="h-5 w-5 text-green-600" />
    <div>
      <p className="font-medium">Google Meet Enabled</p>
      <p className="text-sm">Connected as {solver.googleEmail}</p>
    </div>
  </div>
)}

Not Configured - Shows yellow warning for employed solvers without email:

{solver.employment === "employed" && !solver.googleEmail && (
  <div className="rounded-lg bg-yellow-50 p-4">
    <p className="font-medium">Google Workspace email not configured</p>
    <p className="text-sm">
      Contact an administrator to set up your Google Workspace email.
    </p>
  </div>
)}

Not Available - Shows muted message for contract solvers:

{solver.employment !== "employed" && (
  <div className="rounded-lg bg-muted p-4">
    <p className="text-muted-foreground">
      Google Meet is available for employed (W-2) solvers only.
    </p>
  </div>
)}

Notifications

Control browser and sound notifications for platform events.

Options

SettingDescription
Browser NotificationsPush notifications for new tickets and messages
Sound AlertsAudio cues for incoming tickets and messages

Implementation

Notification preferences are stored locally in the browser:

const [notificationsEnabled, setNotificationsEnabled] = useState(true);
const [soundEnabled, setSoundEnabled] = useState(true);

return (
  <>
    <div className="flex items-center justify-between">
      <div>
        <Label htmlFor="notifications">Browser Notifications</Label>
        <p className="text-sm text-muted-foreground">
          Get notified about new tickets and messages
        </p>
      </div>
      <Switch
        id="notifications"
        checked={notificationsEnabled}
        onCheckedChange={setNotificationsEnabled}
      />
    </div>
    <p className="text-xs text-muted-foreground">
      Note: Notification preferences are stored locally in your browser.
    </p>
  </>
);

Payment Settings

Stripe Connect integration status for receiving payouts.

Connected State

When Stripe is connected, shows success banner and link to Stripe Dashboard:

{solver.stripeConnectId ? (
  <div className="space-y-4">
    <div className="flex items-center gap-3 rounded-lg bg-green-50 p-4">
      <CheckCircle className="h-5 w-5 text-green-600" />
      <div>
        <p className="font-medium">Stripe Connected</p>
        <p className="text-sm">
          Your payout account is set up and ready to receive payments.
        </p>
      </div>
    </div>
    <Button variant="outline" asChild>
      <a href="https://dashboard.stripe.com" target="_blank">
        <ExternalLink className="mr-2 h-4 w-4" />
        Manage in Stripe Dashboard
      </a>
    </Button>
  </div>
)}

Not Connected State

Shows warning and connect button:

{!solver.stripeConnectId && (
  <div className="space-y-4">
    <div className="rounded-lg bg-yellow-50 p-4">
      <p className="font-medium">Payout account not connected</p>
      <p className="text-sm">
        Connect your Stripe account to receive payouts.
      </p>
    </div>
    <Button>Connect Stripe Account</Button>
  </div>
)}

Security

Account security is managed through Clerk's user management interface.

Features Available via Clerk

  • Password changes
  • Two-factor authentication (2FA)
  • Connected accounts (Google, etc.)
  • Session management
<Card>
  <CardHeader>
    <CardTitle className="flex items-center gap-2">
      <Shield className="h-5 w-5" />
      Security
    </CardTitle>
  </CardHeader>
  <CardContent>
    <p className="text-sm text-muted-foreground">
      Account security is managed through Clerk.
    </p>
    <Button variant="outline" asChild>
      <a href="/user" target="_blank">
        <ExternalLink className="mr-2 h-4 w-4" />
        Manage Security Settings
      </a>
    </Button>
  </CardContent>
</Card>

Help & Support

Quick access to documentation and support channels.

LinkDestination
View Documentation/docs - Platform documentation
Contact Supportmailto:support@savvysolve.io
<div className="grid gap-3 sm:grid-cols-2">
  <Button variant="outline" asChild>
    <a href="/docs" target="_blank">
      <ExternalLink className="mr-2 h-4 w-4" />
      View Documentation
    </a>
  </Button>
  <Button variant="outline" asChild>
    <a href="mailto:support@savvysolve.io">
      <ExternalLink className="mr-2 h-4 w-4" />
      Contact Support
    </a>
  </Button>
</div>

Loading State

Displays skeleton placeholders while data loads:

if (isLoading) {
  return (
    <div className="space-y-6">
      <Skeleton className="h-8 w-48" />
      <Skeleton className="h-48 w-full" />
      <Skeleton className="h-48 w-full" />
    </div>
  );
}

UI Components Used

  • Card, CardHeader, CardContent, CardTitle, CardDescription
  • Button - Action buttons and external links
  • RadioGroup, RadioGroupItem - Call preference selection
  • Switch - Notification toggles
  • Label - Form field labels
  • Skeleton - Loading placeholders

File Location

app/(authenticated)/dashboard/settings/
└── page.tsx    # Settings page component

On this page