Skip to content

Commit 5fd7469

Browse files
committed
Polish customer dashboard command center layout
1 parent 2a7c69f commit 5fd7469

13 files changed

Lines changed: 299 additions & 63 deletions

File tree

app/app/page.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ export default async function AppHomePage({
146146

147147
const successfulLeadCount = allLeads.filter((lead) => lead.ownerNotifiedAt || lead.notifiedAt).length;
148148
const systemStatus = getCustomerSystemStatus(business, successfulLeadCount);
149-
const metrics = buildRecoveryMetrics(allLeads);
149+
const metrics = buildRecoveryMetrics(allLeads, business.averageJobValueCents);
150150

151151
const attentionLeads = allLeads
152152
.filter((lead) => isLeadOpenStatus(lead.status))
@@ -164,7 +164,7 @@ export default async function AppHomePage({
164164

165165
return rightPriority.activityAt - leftPriority.activityAt;
166166
})
167-
.slice(0, 5)
167+
.slice(0, 4)
168168
.map((lead) => toLeadCard(lead, demoMode));
169169

170170
const queueAnchor =
@@ -191,24 +191,24 @@ export default async function AppHomePage({
191191
key: 'phone-line',
192192
label: 'Phone line connected',
193193
detail: phoneLineConnected
194-
? 'CallbackCloser has a business line ready for missed-call recovery.'
195-
: 'Connect the business line that should trigger missed-call recovery.',
194+
? 'Business line ready.'
195+
: 'Connect the line that should trigger missed-call recovery.',
196196
state: phoneLineConnected ? ('complete' as const) : ('pending' as const),
197197
},
198198
{
199199
key: 'owner-alerts',
200200
label: 'Owner alerts ready',
201201
detail: ownerAlertsReady
202-
? 'The owner alert route is ready for qualified lead handoffs.'
203-
: 'Add an owner phone or email so lead handoffs land in the right place.',
202+
? 'Owner handoff route ready.'
203+
: 'Add an owner phone or email for lead handoffs.',
204204
state: ownerAlertsReady ? ('complete' as const) : ('pending' as const),
205205
},
206206
{
207207
key: 'texting-activation',
208208
label: 'Texting activation in progress',
209209
detail:
210210
systemStatus.key === 'live'
211-
? 'Texting is live and recovering missed calls now.'
211+
? 'Texting is live.'
212212
: systemStatus.description,
213213
state:
214214
systemStatus.key === 'live'

app/app/settings/actions.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ManagedTwilioStatus, TwilioAccountMode, TwilioNumberSetupMode } from '@
88
import { requireAdmin } from '@/lib/admin';
99
import { logAuditEvent } from '@/lib/audit-log';
1010
import { requireBusiness } from '@/lib/auth';
11+
import { averageJobValueDollarsToCents } from '@/lib/business-settings';
1112
import { db } from '@/lib/db';
1213
import { formatPhoneDetail, maskSid, recordBusinessOperatorEvent } from '@/lib/operator-events';
1314
import { maskPhoneForAudit, normalizePhoneNumber, normalizePhoneNumberToE164 } from '@/lib/phone';
@@ -86,6 +87,7 @@ export async function saveBusinessSettingsAction(formData: FormData) {
8687
forwardingNumber: normalizePhoneNumber(parsed.data.forwardingNumber),
8788
notifyPhone: normalizePhoneNumber(parsed.data.notifyPhone || '') || null,
8889
missedCallSeconds: parsed.data.missedCallSeconds,
90+
averageJobValueCents: averageJobValueDollarsToCents(parsed.data.averageJobValue),
8991
serviceLabel1: parsed.data.serviceLabel1,
9092
serviceLabel2: parsed.data.serviceLabel2,
9193
serviceLabel3: parsed.data.serviceLabel3,
@@ -115,6 +117,7 @@ export async function saveBusinessSettingsAction(formData: FormData) {
115117
});
116118

117119
revalidatePath('/app/settings');
120+
revalidatePath('/app');
118121
revalidatePath('/app/leads');
119122
revalidatePath(`/app/leads`);
120123
revalidatePath('/app/call-flow');

app/app/settings/page.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { db } from '@/lib/db';
1818
import { getManagedTextingNumber, managedTwilioStatusLabels } from '@/lib/managed-twilio-status';
1919
import { formatPhoneForDisplay } from '@/lib/phone';
2020
import { isPortfolioDemoMode } from '@/lib/portfolio-demo';
21+
import { averageJobValueCentsToDollars } from '@/lib/business-settings';
2122

2223
import {
2324
buyTwilioNumberAction,
@@ -85,6 +86,7 @@ function getBadgeVariant(tone: TwilioSetupTone) {
8586

8687
export default async function SettingsPage({ searchParams }: { searchParams?: Record<string, string | string[] | undefined> }) {
8788
const business = await requireBusiness();
89+
const averageJobValue = averageJobValueCentsToDollars(business.averageJobValueCents);
8890
const demoMode = isPortfolioDemoMode();
8991
const adminSession = demoMode ? null : await getAdminSession();
9092
const error = typeof searchParams?.error === 'string' ? searchParams.error : undefined;
@@ -604,6 +606,20 @@ export default async function SettingsPage({ searchParams }: { searchParams?: Re
604606
<Label htmlFor="settingsMissedCallSeconds">Missed-call timeout (seconds)</Label>
605607
<Input id="settingsMissedCallSeconds" name="missedCallSeconds" type="number" min={5} max={90} defaultValue={business.missedCallSeconds} required />
606608
</div>
609+
<div>
610+
<Label htmlFor="settingsAverageJobValue">Average job value</Label>
611+
<Input
612+
id="settingsAverageJobValue"
613+
name="averageJobValue"
614+
type="number"
615+
min={1}
616+
max={100000}
617+
step={1}
618+
defaultValue={averageJobValue ?? ''}
619+
placeholder="500"
620+
/>
621+
<p className="mt-2 text-xs text-muted-foreground">Used to estimate recovered revenue on your dashboard.</p>
622+
</div>
607623
<div>
608624
<Label htmlFor="settingsServiceLabel1">Service option 1</Label>
609625
<Input id="settingsServiceLabel1" name="serviceLabel1" defaultValue={business.serviceLabel1} required />

0 commit comments

Comments
 (0)