Connection status
Whether Ascern can still read a member's mail, calendar or meetings, when it last did, and the one thing to do about it. A row in Settings, a dot in the account menu, a banner across the app while it needs action.
Playground
Change the controls to try each prop. The code under the preview updates as you go and lists only the props you changed; copy it into your page.
GmailConnected
Last synced 5 min ago
import { ConnectionStatus } from '@/ui/connection-status';<ConnectionStatus service="Gmail" lastSynced="5 min ago" />Row
Settings › Connections and the top of Inbox and Meetings: the service, its state in words, the account, the last sync and one action. Connected offers Sync now, not connected offers Connect.
GmailConnected
maya@northbridge.co
Last synced 5 min ago
Google CalendarSyncing
maya@northbridge.co
Syncing now · last synced 2 h ago
EchoNot connected
import { EnvelopeSimpleIcon, CalendarBlankIcon, WaveformIcon } from '@phosphor-icons/react';
import { ConnectionStatus } from '@/ui/connection-status';
// Settings › Connections: one row per service, each with its state, its last sync and its one action.
export default function ConnectionStatusRow() {
return (
<div className="flex w-full flex-col divide-y divide-border rounded-large px-200 inset-ring inset-ring-border">
<ConnectionStatus service="Gmail" account="maya@northbridge.co" status="connected" lastSynced="5 min ago" icon={<EnvelopeSimpleIcon />} onSyncNow={() => {}} />
<ConnectionStatus service="Google Calendar" account="maya@northbridge.co" status="syncing" lastSynced="2 h ago" icon={<CalendarBlankIcon />} onSyncNow={() => {}} />
<ConnectionStatus service="Echo" status="disconnected" icon={<WaveformIcon />} onConnect={() => {}} />
</div>
);
}Needs reconnect and failed
The provider stopped the connection (an expired token), or the last sync didn't finish. The line says why and how long nothing new has come in; Reconnect is the one way out.
GmailNeeds reconnect
maya@northbridge.co
Google stopped the connection. Nothing new since 3 days ago.
Google CalendarSync failed
maya@northbridge.co
The last sync didn’t finish. Nothing new since yesterday.
import { CalendarBlankIcon, EnvelopeSimpleIcon } from '@phosphor-icons/react';
import { ConnectionStatus } from '@/ui/connection-status';
// The provider stopped the connection (an expired token), or the last sync failed. Reconnect is the one way out.
export default function ConnectionStatusAttention() {
return (
<div className="flex w-full flex-col divide-y divide-border rounded-large px-200 inset-ring inset-ring-border">
<ConnectionStatus service="Gmail" account="maya@northbridge.co" status="needs-reconnect" reason="Google stopped the connection." lastSynced="3 days ago" icon={<EnvelopeSimpleIcon />} onReconnect={() => {}} />
<ConnectionStatus service="Google Calendar" account="maya@northbridge.co" status="failed" lastSynced="yesterday" icon={<CalendarBlankIcon />} onReconnect={() => {}} />
</div>
);
}Sync now
Press Sync now: the button keeps its width and spins, the state reads Syncing, then the last sync updates.
GmailConnected
maya@northbridge.co
Last synced 2 h ago
import { EnvelopeSimpleIcon } from '@phosphor-icons/react';
import { useState } from 'react';
import { ConnectionStatus } from '@/ui/connection-status';
// Press Sync now: the button holds its width and spins, the state reads Syncing, then the last sync updates.
export default function ConnectionStatusSync() {
const [syncing, setSyncing] = useState(false);
const [last, setLast] = useState('2 h ago');
const sync = () => {
setSyncing(true);
setTimeout(() => {
setSyncing(false);
setLast('just now');
}, 1500);
};
return (
<div className="w-full rounded-large px-200 inset-ring inset-ring-border">
<ConnectionStatus service="Gmail" account="maya@northbridge.co" status={syncing ? 'syncing' : 'connected'} lastSynced={last} icon={<EnvelopeSimpleIcon />} onSyncNow={sync} />
</div>
);
}Badge
variant="badge" for the account menu: a dot and the state in words. A consultant who never opens Inbox still sees that mail stopped.
import { ConnectionStatus } from '@/ui/connection-status';
// In the account menu: a dot and the state in words, so a consultant who never opens Inbox still sees it.
export default function ConnectionStatusBadge() {
return (
<div className="flex flex-col gap-100">
<ConnectionStatus variant="badge" service="Gmail" status="connected" />
<ConnectionStatus variant="badge" service="Google Calendar" status="syncing" />
<ConnectionStatus variant="badge" service="Echo" status="needs-reconnect" />
<ConnectionStatus variant="badge" service="Outlook" status="failed" />
<ConnectionStatus variant="badge" service="Zoom" status="disconnected" />
</div>
);
}Banner
variant="banner" across the app while a connection needs reconnecting or failed. It shows nothing in any other state, so the app can always render it. Press Reconnect, then Replay.
import { useState } from 'react';
import { Button } from '@/ui/button';
import { ConnectionStatus } from '@/ui/connection-status';
// Across the app while a connection needs action. Press Reconnect: once it is fixed the banner goes.
export default function ConnectionStatusBanner() {
const [status, setStatus] = useState<'needs-reconnect' | 'connected'>('needs-reconnect');
return (
<div className="flex w-full flex-col items-start gap-200">
<ConnectionStatus variant="banner" service="Gmail" status={status} onReconnect={() => setStatus('connected')} />
{status === 'connected' ? (
<Button size="sm" onClick={() => setStatus('needs-reconnect')}>
Replay
</Button>
) : null}
</div>
);
}Banner
A full-width strip for a state that covers everything below it: the whole app when you are offline, or a whole record when it is archived or must not be contacted. The largest of three message levels.
Duplicate notice
A row that appears under a Company you just saved when Ascern finds one that looks the same. It points it out and never blocks the save.