feat: add demo data for emails, files, filters, identities, mailboxes, vacation responses, and JMAP client interface
- Created demo emails with various states (inbox, sent, drafts, trash, etc.) in `emails.ts`. - Added demo file nodes representing directories and files in `files.ts`. - Implemented demo Sieve capabilities and scripts in `filters.ts`. - Defined demo identities for users in `identities.ts`. - Established demo mailboxes with permissions and counts in `mailboxes.ts`. - Created a demo vacation response in `vacation.ts`. - Introduced a comprehensive JMAP client interface in `client-interface.ts` to standardize interactions with the JMAP API.
This commit is contained in:
@@ -0,0 +1,274 @@
|
||||
import type { Calendar, CalendarEvent } from '@/lib/jmap/types';
|
||||
import { demoDate, demoISODate } from '../demo-utils';
|
||||
|
||||
export function createDemoCalendars(): Calendar[] {
|
||||
return [
|
||||
{
|
||||
id: 'demo-calendar-personal',
|
||||
name: 'Personal',
|
||||
description: null,
|
||||
color: '#3b82f6',
|
||||
sortOrder: 1,
|
||||
isSubscribed: true,
|
||||
isVisible: true,
|
||||
isDefault: true,
|
||||
includeInAvailability: 'all',
|
||||
defaultAlertsWithTime: null,
|
||||
defaultAlertsWithoutTime: null,
|
||||
timeZone: null,
|
||||
shareWith: null,
|
||||
myRights: { mayReadFreeBusy: true, mayReadItems: true, mayWriteAll: true, mayWriteOwn: true, mayUpdatePrivate: true, mayRSVP: true, mayAdmin: true, mayDelete: false },
|
||||
},
|
||||
{
|
||||
id: 'demo-calendar-work',
|
||||
name: 'Work',
|
||||
description: null,
|
||||
color: '#22c55e',
|
||||
sortOrder: 2,
|
||||
isSubscribed: true,
|
||||
isVisible: true,
|
||||
isDefault: false,
|
||||
includeInAvailability: 'all',
|
||||
defaultAlertsWithTime: null,
|
||||
defaultAlertsWithoutTime: null,
|
||||
timeZone: null,
|
||||
shareWith: null,
|
||||
myRights: { mayReadFreeBusy: true, mayReadItems: true, mayWriteAll: true, mayWriteOwn: true, mayUpdatePrivate: true, mayRSVP: true, mayAdmin: true, mayDelete: true },
|
||||
},
|
||||
{
|
||||
id: 'demo-calendar-birthdays',
|
||||
name: 'Birthdays',
|
||||
description: null,
|
||||
color: '#eab308',
|
||||
sortOrder: 3,
|
||||
isSubscribed: true,
|
||||
isVisible: true,
|
||||
isDefault: false,
|
||||
includeInAvailability: 'none',
|
||||
defaultAlertsWithTime: null,
|
||||
defaultAlertsWithoutTime: null,
|
||||
timeZone: null,
|
||||
shareWith: null,
|
||||
myRights: { mayReadFreeBusy: true, mayReadItems: true, mayWriteAll: true, mayWriteOwn: true, mayUpdatePrivate: true, mayRSVP: true, mayAdmin: true, mayDelete: true },
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function createDemoCalendarEvents(): CalendarEvent[] {
|
||||
const baseEvent = {
|
||||
'@type': 'Event' as const,
|
||||
descriptionContentType: 'text/plain',
|
||||
isDraft: false,
|
||||
isOrigin: true,
|
||||
sequence: 0,
|
||||
status: 'confirmed' as const,
|
||||
freeBusyStatus: 'busy' as const,
|
||||
privacy: 'public' as const,
|
||||
color: null,
|
||||
keywords: null,
|
||||
categories: null,
|
||||
locale: null,
|
||||
replyTo: null,
|
||||
organizerCalendarAddress: null,
|
||||
participants: null,
|
||||
mayInviteSelf: false,
|
||||
mayInviteOthers: false,
|
||||
hideAttendees: false,
|
||||
recurrenceId: null,
|
||||
recurrenceIdTimeZone: null,
|
||||
recurrenceRules: null,
|
||||
recurrenceOverrides: null,
|
||||
excludedRecurrenceRules: null,
|
||||
useDefaultAlerts: true,
|
||||
alerts: null,
|
||||
locations: null,
|
||||
virtualLocations: null,
|
||||
links: null,
|
||||
relatedTo: null,
|
||||
};
|
||||
|
||||
return [
|
||||
// ── Personal calendar ──────────────────────────────────────
|
||||
{
|
||||
...baseEvent,
|
||||
id: 'demo-event-1',
|
||||
calendarIds: { 'demo-calendar-personal': true },
|
||||
uid: 'demo-event-1@example.com',
|
||||
title: 'Dentist Appointment',
|
||||
description: 'Regular checkup at Dr. Smith\'s office',
|
||||
created: demoDate(-7),
|
||||
updated: demoDate(-7),
|
||||
start: demoISODate(2, 10, 0),
|
||||
utcStart: demoDate(2, 10),
|
||||
utcEnd: demoDate(2, 11),
|
||||
duration: 'PT1H',
|
||||
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
showWithoutTime: false,
|
||||
locations: { loc1: { '@type': 'Location', name: 'Dr. Smith Dental Clinic', description: '123 Medical Plaza', locationTypes: null, coordinates: null, timeZone: null, links: null, relativeTo: null } },
|
||||
},
|
||||
{
|
||||
...baseEvent,
|
||||
id: 'demo-event-2',
|
||||
calendarIds: { 'demo-calendar-personal': true },
|
||||
uid: 'demo-event-2@example.com',
|
||||
title: 'Birthday Party',
|
||||
description: 'Emma\'s birthday celebration',
|
||||
created: demoDate(-10),
|
||||
updated: demoDate(-10),
|
||||
start: demoISODate(5),
|
||||
utcStart: demoDate(5),
|
||||
utcEnd: demoDate(6),
|
||||
duration: 'P1D',
|
||||
timeZone: null,
|
||||
showWithoutTime: true,
|
||||
freeBusyStatus: 'free' as const,
|
||||
},
|
||||
{
|
||||
...baseEvent,
|
||||
id: 'demo-event-3',
|
||||
calendarIds: { 'demo-calendar-personal': true },
|
||||
uid: 'demo-event-3@example.com',
|
||||
title: 'Weekend Trip',
|
||||
description: 'Road trip to the mountains',
|
||||
created: demoDate(-5),
|
||||
updated: demoDate(-5),
|
||||
start: demoISODate(8),
|
||||
utcStart: demoDate(8),
|
||||
utcEnd: demoDate(10),
|
||||
duration: 'P2D',
|
||||
timeZone: null,
|
||||
showWithoutTime: true,
|
||||
freeBusyStatus: 'busy' as const,
|
||||
},
|
||||
|
||||
// ── Work calendar ──────────────────────────────────────────
|
||||
{
|
||||
...baseEvent,
|
||||
id: 'demo-event-4',
|
||||
calendarIds: { 'demo-calendar-work': true },
|
||||
uid: 'demo-event-4@example.com',
|
||||
title: 'Weekly Standup',
|
||||
description: 'Team sync-up meeting',
|
||||
created: demoDate(-30),
|
||||
updated: demoDate(-1),
|
||||
start: demoISODate(1, 9, 30),
|
||||
utcStart: demoDate(1, 9, 30),
|
||||
utcEnd: demoDate(1, 10, 0),
|
||||
duration: 'PT30M',
|
||||
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
showWithoutTime: false,
|
||||
recurrenceRules: [{
|
||||
'@type': 'RecurrenceRule',
|
||||
frequency: 'weekly',
|
||||
interval: 1,
|
||||
rscale: 'gregorian',
|
||||
skip: 'omit',
|
||||
firstDayOfWeek: 'mo',
|
||||
byDay: [{ day: 'mo' }],
|
||||
byMonthDay: null,
|
||||
byMonth: null,
|
||||
byYearDay: null,
|
||||
byWeekNo: null,
|
||||
byHour: null,
|
||||
byMinute: null,
|
||||
bySecond: null,
|
||||
bySetPosition: null,
|
||||
count: null,
|
||||
until: null,
|
||||
}],
|
||||
virtualLocations: { vl1: { '@type': 'VirtualLocation', name: 'Zoom', uri: 'https://zoom.example/123456', description: 'Weekly standup room', features: null } },
|
||||
},
|
||||
{
|
||||
...baseEvent,
|
||||
id: 'demo-event-5',
|
||||
calendarIds: { 'demo-calendar-work': true },
|
||||
uid: 'demo-event-5@example.com',
|
||||
title: 'Quarterly Review',
|
||||
description: 'Q4 performance review and planning session',
|
||||
created: demoDate(-14),
|
||||
updated: demoDate(-3),
|
||||
start: demoISODate(4, 14, 0),
|
||||
utcStart: demoDate(4, 14),
|
||||
utcEnd: demoDate(4, 16),
|
||||
duration: 'PT2H',
|
||||
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
showWithoutTime: false,
|
||||
participants: {
|
||||
p1: {
|
||||
'@type': 'Participant', name: 'Demo User', email: 'demo@example.com', calendarAddress: null, description: null, sendTo: null,
|
||||
kind: 'individual', roles: { attendee: true }, participationStatus: 'accepted', participationComment: null,
|
||||
expectReply: false, scheduleAgent: 'server', scheduleForceSend: false, scheduleId: null, scheduleSequence: 0,
|
||||
scheduleStatus: null, scheduleUpdated: null, invitedBy: null, delegatedTo: null, delegatedFrom: null, memberOf: null,
|
||||
locationId: null, language: null, links: null,
|
||||
},
|
||||
p2: {
|
||||
'@type': 'Participant', name: 'Alice Johnson', email: 'alice.johnson@example.com', calendarAddress: null, description: null, sendTo: null,
|
||||
kind: 'individual', roles: { owner: true }, participationStatus: 'accepted', participationComment: null,
|
||||
expectReply: false, scheduleAgent: 'server', scheduleForceSend: false, scheduleId: null, scheduleSequence: 0,
|
||||
scheduleStatus: null, scheduleUpdated: null, invitedBy: null, delegatedTo: null, delegatedFrom: null, memberOf: null,
|
||||
locationId: null, language: null, links: null,
|
||||
},
|
||||
p3: {
|
||||
'@type': 'Participant', name: 'Bob Chen', email: 'bob.chen@example.com', calendarAddress: null, description: null, sendTo: null,
|
||||
kind: 'individual', roles: { attendee: true }, participationStatus: 'tentative', participationComment: null,
|
||||
expectReply: true, scheduleAgent: 'server', scheduleForceSend: false, scheduleId: null, scheduleSequence: 0,
|
||||
scheduleStatus: null, scheduleUpdated: null, invitedBy: null, delegatedTo: null, delegatedFrom: null, memberOf: null,
|
||||
locationId: null, language: null, links: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
...baseEvent,
|
||||
id: 'demo-event-6',
|
||||
calendarIds: { 'demo-calendar-work': true },
|
||||
uid: 'demo-event-6@example.com',
|
||||
title: 'Lunch Meeting with Sarah',
|
||||
description: 'Design review over lunch',
|
||||
created: demoDate(-3),
|
||||
updated: demoDate(-3),
|
||||
start: demoISODate(3, 12, 0),
|
||||
utcStart: demoDate(3, 12),
|
||||
utcEnd: demoDate(3, 13),
|
||||
duration: 'PT1H',
|
||||
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
showWithoutTime: false,
|
||||
locations: { loc1: { '@type': 'Location', name: 'The Garden Bistro', description: '123 Oak Street', locationTypes: null, coordinates: null, timeZone: null, links: null, relativeTo: null } },
|
||||
},
|
||||
|
||||
// ── Birthdays calendar ─────────────────────────────────────
|
||||
{
|
||||
...baseEvent,
|
||||
id: 'demo-event-7',
|
||||
calendarIds: { 'demo-calendar-birthdays': true },
|
||||
uid: 'demo-event-7@example.com',
|
||||
title: 'Alice Johnson\'s Birthday',
|
||||
description: '',
|
||||
created: demoDate(-30),
|
||||
updated: demoDate(-30),
|
||||
start: demoISODate(12),
|
||||
utcStart: demoDate(12),
|
||||
utcEnd: demoDate(13),
|
||||
duration: 'P1D',
|
||||
timeZone: null,
|
||||
showWithoutTime: true,
|
||||
freeBusyStatus: 'free' as const,
|
||||
},
|
||||
{
|
||||
...baseEvent,
|
||||
id: 'demo-event-8',
|
||||
calendarIds: { 'demo-calendar-birthdays': true },
|
||||
uid: 'demo-event-8@example.com',
|
||||
title: 'Carlos Rivera\'s Birthday',
|
||||
description: '',
|
||||
created: demoDate(-30),
|
||||
updated: demoDate(-30),
|
||||
start: demoISODate(-3),
|
||||
utcStart: demoDate(-3),
|
||||
utcEnd: demoDate(-2),
|
||||
duration: 'P1D',
|
||||
timeZone: null,
|
||||
showWithoutTime: true,
|
||||
freeBusyStatus: 'free' as const,
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
import type { ContactCard, AddressBook } from '@/lib/jmap/types';
|
||||
|
||||
export function createDemoAddressBooks(): AddressBook[] {
|
||||
return [
|
||||
{
|
||||
id: 'demo-addressbook-personal',
|
||||
name: 'Personal',
|
||||
isDefault: true,
|
||||
isSubscribed: true,
|
||||
sortOrder: 1,
|
||||
myRights: { mayRead: true, mayWrite: true, mayShare: true, mayDelete: false },
|
||||
},
|
||||
{
|
||||
id: 'demo-addressbook-work',
|
||||
name: 'Work',
|
||||
isDefault: false,
|
||||
isSubscribed: true,
|
||||
sortOrder: 2,
|
||||
myRights: { mayRead: true, mayWrite: true, mayShare: true, mayDelete: true },
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function createDemoContacts(): ContactCard[] {
|
||||
return [
|
||||
// ── Personal address book ──────────────────────────────────
|
||||
{
|
||||
id: 'demo-contact-1',
|
||||
addressBookIds: { 'demo-addressbook-personal': true },
|
||||
kind: 'individual',
|
||||
name: { components: [{ kind: 'given', value: 'Alice' }, { kind: 'surname', value: 'Johnson' }] },
|
||||
emails: { e1: { address: 'alice.johnson@example.com', contexts: { work: true }, pref: 1 } },
|
||||
phones: { p1: { number: '+1-555-0101', features: { voice: true }, contexts: { work: true } } },
|
||||
organizations: { o1: { name: 'Acme Corp', units: [{ name: 'Engineering' }] } },
|
||||
titles: { t1: { name: 'Senior Engineer', kind: 'title' } },
|
||||
anniversaries: { a1: { kind: 'birth', date: { year: 1990, month: 3, day: 15 } } },
|
||||
},
|
||||
{
|
||||
id: 'demo-contact-2',
|
||||
addressBookIds: { 'demo-addressbook-personal': true },
|
||||
kind: 'individual',
|
||||
name: { components: [{ kind: 'given', value: 'Bob' }, { kind: 'surname', value: 'Chen' }] },
|
||||
emails: {
|
||||
e1: { address: 'bob.chen@example.com', contexts: { work: true }, pref: 1 },
|
||||
e2: { address: 'bob.personal@email.example', contexts: { private: true } },
|
||||
},
|
||||
phones: {
|
||||
p1: { number: '+1-555-0102', features: { voice: true }, contexts: { work: true } },
|
||||
p2: { number: '+1-555-0103', features: { cell: true }, contexts: { private: true } },
|
||||
},
|
||||
organizations: { o1: { name: 'Acme Corp', units: [{ name: 'Backend Team' }] } },
|
||||
titles: { t1: { name: 'Staff Engineer', kind: 'title' } },
|
||||
},
|
||||
{
|
||||
id: 'demo-contact-3',
|
||||
addressBookIds: { 'demo-addressbook-personal': true },
|
||||
kind: 'individual',
|
||||
name: { components: [{ kind: 'given', value: 'Sarah' }, { kind: 'surname', value: 'Kim' }] },
|
||||
emails: { e1: { address: 'sarah.kim@example.com', pref: 1 } },
|
||||
phones: { p1: { number: '+1-555-0104', features: { voice: true } } },
|
||||
organizations: { o1: { name: 'DesignCo' } },
|
||||
titles: { t1: { name: 'UX Designer', kind: 'title' } },
|
||||
},
|
||||
{
|
||||
id: 'demo-contact-4',
|
||||
addressBookIds: { 'demo-addressbook-personal': true },
|
||||
kind: 'individual',
|
||||
name: { components: [{ kind: 'given', value: 'Carlos' }, { kind: 'surname', value: 'Rivera' }] },
|
||||
emails: { e1: { address: 'carlos.rivera@example.com', pref: 1 } },
|
||||
phones: { p1: { number: '+1-555-0105', features: { cell: true } } },
|
||||
notes: { n1: { note: 'Met at the DevConf 2024 conference' } },
|
||||
},
|
||||
{
|
||||
id: 'demo-contact-5',
|
||||
addressBookIds: { 'demo-addressbook-personal': true },
|
||||
kind: 'individual',
|
||||
name: { components: [{ kind: 'given', value: 'Emma' }, { kind: 'surname', value: 'Wilson' }] },
|
||||
emails: { e1: { address: 'emma.wilson@example.com', pref: 1 } },
|
||||
addresses: {
|
||||
a1: {
|
||||
components: [
|
||||
{ kind: 'number', value: '456' },
|
||||
{ kind: 'name', value: 'Elm Street' },
|
||||
{ kind: 'locality', value: 'Springfield' },
|
||||
{ kind: 'region', value: 'IL' },
|
||||
{ kind: 'postcode', value: '62701' },
|
||||
],
|
||||
contexts: { private: true },
|
||||
},
|
||||
},
|
||||
anniversaries: { a1: { kind: 'birth', date: { month: 7, day: 22 } } },
|
||||
},
|
||||
{
|
||||
id: 'demo-contact-6',
|
||||
addressBookIds: { 'demo-addressbook-personal': true },
|
||||
kind: 'individual',
|
||||
name: { components: [{ kind: 'given', value: 'David' }, { kind: 'surname', value: 'Park' }] },
|
||||
emails: { e1: { address: 'david.park@example.com', pref: 1 } },
|
||||
phones: { p1: { number: '+82-10-1234-5678', features: { cell: true } } },
|
||||
},
|
||||
{
|
||||
id: 'demo-contact-7',
|
||||
addressBookIds: { 'demo-addressbook-personal': true },
|
||||
kind: 'org',
|
||||
name: { components: [{ kind: 'surname', value: 'Local Coffee Shop' }] },
|
||||
emails: { e1: { address: 'hello@localcoffee.example', pref: 1 } },
|
||||
phones: { p1: { number: '+1-555-0200', features: { voice: true } } },
|
||||
addresses: {
|
||||
a1: {
|
||||
components: [
|
||||
{ kind: 'number', value: '789' },
|
||||
{ kind: 'name', value: 'Main Street' },
|
||||
{ kind: 'locality', value: 'Anytown' },
|
||||
{ kind: 'region', value: 'CA' },
|
||||
{ kind: 'postcode', value: '90210' },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'demo-contact-8',
|
||||
addressBookIds: { 'demo-addressbook-personal': true },
|
||||
kind: 'individual',
|
||||
name: { components: [{ kind: 'given', value: 'Lisa' }, { kind: 'surname', value: 'Tanaka' }] },
|
||||
emails: { e1: { address: 'lisa.tanaka@example.com', pref: 1 } },
|
||||
},
|
||||
|
||||
// ── Work address book ──────────────────────────────────────
|
||||
{
|
||||
id: 'demo-contact-9',
|
||||
addressBookIds: { 'demo-addressbook-work': true },
|
||||
kind: 'individual',
|
||||
name: { components: [{ kind: 'given', value: 'Michael' }, { kind: 'surname', value: 'Torres' }] },
|
||||
emails: { e1: { address: 'michael.torres@company.example', contexts: { work: true }, pref: 1 } },
|
||||
phones: { p1: { number: '+1-555-0301', features: { voice: true }, contexts: { work: true } } },
|
||||
organizations: { o1: { name: 'Company Inc', units: [{ name: 'Product' }] } },
|
||||
titles: { t1: { name: 'Product Manager', kind: 'title' } },
|
||||
},
|
||||
{
|
||||
id: 'demo-contact-10',
|
||||
addressBookIds: { 'demo-addressbook-work': true },
|
||||
kind: 'individual',
|
||||
name: { components: [{ kind: 'given', value: 'Rachel' }, { kind: 'surname', value: 'Green' }] },
|
||||
emails: { e1: { address: 'rachel.green@company.example', contexts: { work: true }, pref: 1 } },
|
||||
organizations: { o1: { name: 'Company Inc', units: [{ name: 'Marketing' }] } },
|
||||
titles: { t1: { name: 'Marketing Lead', kind: 'title' } },
|
||||
},
|
||||
{
|
||||
id: 'demo-contact-11',
|
||||
addressBookIds: { 'demo-addressbook-work': true },
|
||||
kind: 'individual',
|
||||
name: { components: [{ kind: 'given', value: 'James' }, { kind: 'surname', value: 'Miller' }] },
|
||||
emails: { e1: { address: 'james.miller@company.example', contexts: { work: true }, pref: 1 } },
|
||||
organizations: { o1: { name: 'Company Inc', units: [{ name: 'Engineering' }] } },
|
||||
titles: { t1: { name: 'CTO', kind: 'title' } },
|
||||
},
|
||||
{
|
||||
id: 'demo-contact-12',
|
||||
addressBookIds: { 'demo-addressbook-work': true },
|
||||
kind: 'individual',
|
||||
name: { components: [{ kind: 'given', value: 'Priya' }, { kind: 'surname', value: 'Sharma' }] },
|
||||
emails: { e1: { address: 'priya.sharma@company.example', contexts: { work: true }, pref: 1 } },
|
||||
organizations: { o1: { name: 'Company Inc', units: [{ name: 'QA' }] } },
|
||||
titles: { t1: { name: 'QA Engineer', kind: 'title' } },
|
||||
},
|
||||
{
|
||||
id: 'demo-contact-13',
|
||||
addressBookIds: { 'demo-addressbook-work': true },
|
||||
kind: 'individual',
|
||||
name: { components: [{ kind: 'given', value: 'Ahmed' }, { kind: 'surname', value: 'Hassan' }] },
|
||||
emails: { e1: { address: 'ahmed.hassan@company.example', contexts: { work: true }, pref: 1 } },
|
||||
organizations: { o1: { name: 'Company Inc', units: [{ name: 'DevOps' }] } },
|
||||
titles: { t1: { name: 'DevOps Engineer', kind: 'title' } },
|
||||
},
|
||||
{
|
||||
id: 'demo-contact-14',
|
||||
addressBookIds: { 'demo-addressbook-work': true },
|
||||
kind: 'individual',
|
||||
name: { components: [{ kind: 'given', value: 'Maria' }, { kind: 'surname', value: 'Lopez' }] },
|
||||
emails: { e1: { address: 'maria.lopez@company.example', contexts: { work: true }, pref: 1 } },
|
||||
organizations: { o1: { name: 'Company Inc', units: [{ name: 'HR' }] } },
|
||||
titles: { t1: { name: 'HR Business Partner', kind: 'title' } },
|
||||
},
|
||||
{
|
||||
id: 'demo-contact-15',
|
||||
addressBookIds: { 'demo-addressbook-work': true },
|
||||
kind: 'individual',
|
||||
name: { components: [{ kind: 'given', value: 'Wei' }, { kind: 'surname', value: 'Zhang' }] },
|
||||
emails: { e1: { address: 'wei.zhang@company.example', contexts: { work: true }, pref: 1 } },
|
||||
organizations: { o1: { name: 'Company Inc', units: [{ name: 'Data Science' }] } },
|
||||
titles: { t1: { name: 'Data Scientist', kind: 'title' } },
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
import type { Email } from '@/lib/jmap/types';
|
||||
import { demoDate } from '../demo-utils';
|
||||
|
||||
export function createDemoEmails(): Email[] {
|
||||
const now = new Date();
|
||||
|
||||
return [
|
||||
// ── Inbox ───────────────────────────────────────────────────
|
||||
{
|
||||
id: 'demo-email-1',
|
||||
threadId: 'demo-thread-1',
|
||||
mailboxIds: { 'demo-mailbox-inbox': true },
|
||||
keywords: {},
|
||||
size: 4200,
|
||||
receivedAt: demoDate(0, -2),
|
||||
from: [{ name: 'Bulwark Team', email: 'welcome@bulwark.email' }],
|
||||
to: [{ name: 'Demo User', email: 'demo@example.com' }],
|
||||
subject: 'Welcome to Bulwark Mail!',
|
||||
sentAt: demoDate(0, -2),
|
||||
preview: 'Thanks for trying out Bulwark Mail. This is a demo environment where you can explore all features...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-1', size: 350, type: 'text/plain' }],
|
||||
htmlBody: [{ partId: '2', blobId: 'blob-2', size: 800, type: 'text/html' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Thanks for trying out Bulwark Mail!\n\nThis is a demo environment where you can explore all features without connecting to a real server. All data stays on your device.\n\nFeel free to:\n- Read, compose, and organize emails\n- Manage contacts and calendars\n- Configure filters and settings\n- Try keyboard shortcuts (press ? to see them)\n\nEnjoy exploring!' },
|
||||
'2': { value: '<div><h2>Welcome to Bulwark Mail!</h2><p>Thanks for trying out Bulwark Mail!</p><p>This is a demo environment where you can explore all features without connecting to a real server. <strong>All data stays on your device.</strong></p><p>Feel free to:</p><ul><li>Read, compose, and organize emails</li><li>Manage contacts and calendars</li><li>Configure filters and settings</li><li>Try keyboard shortcuts (press <kbd>?</kbd> to see them)</li></ul><p>Enjoy exploring!</p></div>' },
|
||||
},
|
||||
messageId: '<welcome@demo.bulwark.email>',
|
||||
},
|
||||
{
|
||||
id: 'demo-email-2',
|
||||
threadId: 'demo-thread-2',
|
||||
mailboxIds: { 'demo-mailbox-inbox': true },
|
||||
keywords: { $seen: true },
|
||||
size: 18500,
|
||||
receivedAt: demoDate(-1, -5),
|
||||
from: [{ name: 'TechDigest Weekly', email: 'newsletter@techdigest.example' }],
|
||||
to: [{ name: 'Demo User', email: 'demo@example.com' }],
|
||||
subject: 'This Week in Tech: AI Developments & Open Source Updates',
|
||||
sentAt: demoDate(-1, -5),
|
||||
preview: 'Your weekly roundup of the most important technology news and open source developments...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-3', size: 2400, type: 'text/plain' }],
|
||||
htmlBody: [{ partId: '2', blobId: 'blob-4', size: 5200, type: 'text/html' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'This Week in Tech\n\n1. AI-Powered Code Review Tools\nNew tools are making code reviews faster and more thorough...\n\n2. Open Source Licensing Update\nThe OSI has published new guidelines for AI-generated code...\n\n3. WebAssembly 2.0 Draft\nThe W3C has released the first draft of WebAssembly 2.0...\n\nRead more at techdigest.example' },
|
||||
'2': { value: '<div style="max-width:600px;margin:0 auto;"><h1>This Week in Tech</h1><h3>1. AI-Powered Code Review Tools</h3><p>New tools are making code reviews faster and more thorough, with several open-source options gaining traction.</p><h3>2. Open Source Licensing Update</h3><p>The OSI has published new guidelines for AI-generated code contributions to open source projects.</p><h3>3. WebAssembly 2.0 Draft</h3><p>The W3C has released the first draft of WebAssembly 2.0, promising improved memory management.</p></div>' },
|
||||
},
|
||||
messageId: '<weekly-42@techdigest.example>',
|
||||
},
|
||||
// Thread: Project discussion (3 emails in same thread)
|
||||
{
|
||||
id: 'demo-email-3a',
|
||||
threadId: 'demo-thread-3',
|
||||
mailboxIds: { 'demo-mailbox-inbox': true },
|
||||
keywords: { $seen: true },
|
||||
size: 3100,
|
||||
receivedAt: demoDate(-3, -10),
|
||||
from: [{ name: 'Alice Johnson', email: 'alice.johnson@example.com' }],
|
||||
to: [{ name: 'Demo User', email: 'demo@example.com' }, { name: 'Bob Chen', email: 'bob.chen@example.com' }],
|
||||
subject: 'Q4 Project Timeline',
|
||||
sentAt: demoDate(-3, -10),
|
||||
preview: 'Hi team, I wanted to share the updated timeline for our Q4 deliverables...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-5', size: 450, type: 'text/plain' }],
|
||||
htmlBody: [{ partId: '2', blobId: 'blob-6', size: 650, type: 'text/html' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Hi team,\n\nI wanted to share the updated timeline for our Q4 deliverables:\n\n- Phase 1: Design review — Oct 15\n- Phase 2: Development — Nov 1-30\n- Phase 3: Testing — Dec 1-15\n- Phase 4: Launch — Dec 20\n\nPlease review and let me know if you see any conflicts.\n\nBest,\nAlice' },
|
||||
'2': { value: '<p>Hi team,</p><p>I wanted to share the updated timeline for our Q4 deliverables:</p><ul><li>Phase 1: Design review — Oct 15</li><li>Phase 2: Development — Nov 1-30</li><li>Phase 3: Testing — Dec 1-15</li><li>Phase 4: Launch — Dec 20</li></ul><p>Please review and let me know if you see any conflicts.</p><p>Best,<br>Alice</p>' },
|
||||
},
|
||||
messageId: '<q4-timeline-1@example.com>',
|
||||
},
|
||||
{
|
||||
id: 'demo-email-3b',
|
||||
threadId: 'demo-thread-3',
|
||||
mailboxIds: { 'demo-mailbox-inbox': true },
|
||||
keywords: { $seen: true },
|
||||
size: 3500,
|
||||
receivedAt: demoDate(-2, -8),
|
||||
from: [{ name: 'Bob Chen', email: 'bob.chen@example.com' }],
|
||||
to: [{ name: 'Alice Johnson', email: 'alice.johnson@example.com' }, { name: 'Demo User', email: 'demo@example.com' }],
|
||||
subject: 'Re: Q4 Project Timeline',
|
||||
sentAt: demoDate(-2, -8),
|
||||
preview: 'Looks good to me! One concern: the testing window might be tight given the holidays...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-7', size: 520, type: 'text/plain' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Looks good to me! One concern: the testing window might be tight given the holidays. Could we start testing a few days earlier?\n\nAlso, should we set up a shared doc for tracking blockers?\n\n— Bob' },
|
||||
},
|
||||
messageId: '<q4-timeline-2@example.com>',
|
||||
inReplyTo: ['<q4-timeline-1@example.com>'],
|
||||
references: ['<q4-timeline-1@example.com>'],
|
||||
},
|
||||
{
|
||||
id: 'demo-email-3c',
|
||||
threadId: 'demo-thread-3',
|
||||
mailboxIds: { 'demo-mailbox-inbox': true },
|
||||
keywords: {},
|
||||
size: 3800,
|
||||
receivedAt: demoDate(-1, -3),
|
||||
from: [{ name: 'Alice Johnson', email: 'alice.johnson@example.com' }],
|
||||
to: [{ name: 'Bob Chen', email: 'bob.chen@example.com' }, { name: 'Demo User', email: 'demo@example.com' }],
|
||||
subject: 'Re: Q4 Project Timeline',
|
||||
sentAt: demoDate(-1, -3),
|
||||
preview: 'Great point Bob. Let\'s move testing to Nov 28. I\'ll create the shared doc today...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-8', size: 400, type: 'text/plain' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Great point Bob. Let\'s move testing to Nov 28. I\'ll create the shared doc today and share the link.\n\nUpdated timeline:\n- Design review: Oct 15\n- Development: Nov 1-27\n- Testing: Nov 28 - Dec 15\n- Launch: Dec 20\n\n— Alice' },
|
||||
},
|
||||
messageId: '<q4-timeline-3@example.com>',
|
||||
inReplyTo: ['<q4-timeline-2@example.com>'],
|
||||
references: ['<q4-timeline-1@example.com>', '<q4-timeline-2@example.com>'],
|
||||
},
|
||||
// Email with attachments
|
||||
{
|
||||
id: 'demo-email-4',
|
||||
threadId: 'demo-thread-4',
|
||||
mailboxIds: { 'demo-mailbox-inbox': true },
|
||||
keywords: {},
|
||||
size: 245000,
|
||||
receivedAt: demoDate(0, -6),
|
||||
from: [{ name: 'Sarah Kim', email: 'sarah.kim@example.com' }],
|
||||
to: [{ name: 'Demo User', email: 'demo@example.com' }],
|
||||
subject: 'Invoice #2024-089 & Project Screenshot',
|
||||
sentAt: demoDate(0, -6),
|
||||
preview: 'Hi, please find attached the invoice for October and a screenshot of the latest prototype...',
|
||||
hasAttachment: true,
|
||||
textBody: [{ partId: '1', blobId: 'blob-9', size: 280, type: 'text/plain' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Hi,\n\nPlease find attached the invoice for October and a screenshot of the latest prototype.\n\nLet me know if you have any questions.\n\nBest regards,\nSarah' },
|
||||
},
|
||||
attachments: [
|
||||
{ partId: 'att-1', blobId: 'demo-blob-att-1', size: 145000, name: 'Invoice-2024-089.pdf', type: 'application/pdf' },
|
||||
{ partId: 'att-2', blobId: 'demo-blob-att-2', size: 89000, name: 'prototype-v3.png', type: 'image/png' },
|
||||
],
|
||||
messageId: '<invoice-089@example.com>',
|
||||
},
|
||||
// Starred email
|
||||
{
|
||||
id: 'demo-email-5',
|
||||
threadId: 'demo-thread-5',
|
||||
mailboxIds: { 'demo-mailbox-inbox': true },
|
||||
keywords: { $seen: true, $flagged: true },
|
||||
size: 2800,
|
||||
receivedAt: demoDate(-2, -1),
|
||||
from: [{ name: 'Carlos Rivera', email: 'carlos.rivera@example.com' }],
|
||||
to: [{ name: 'Demo User', email: 'demo@example.com' }],
|
||||
subject: 'Reminder: Team Dinner Friday',
|
||||
sentAt: demoDate(-2, -1),
|
||||
preview: 'Hey! Just a reminder about our team dinner this Friday at 7 PM at The Garden Bistro...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-10', size: 320, type: 'text/plain' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Hey!\n\nJust a reminder about our team dinner this Friday at 7 PM at The Garden Bistro. I\'ve made a reservation for 8 people.\n\nAddress: 123 Oak Street\n\nLet me know if you can make it!\n\nCheers,\nCarlos' },
|
||||
},
|
||||
messageId: '<dinner-reminder@example.com>',
|
||||
},
|
||||
|
||||
// ── Sent ────────────────────────────────────────────────────
|
||||
{
|
||||
id: 'demo-email-6',
|
||||
threadId: 'demo-thread-6',
|
||||
mailboxIds: { 'demo-mailbox-sent': true },
|
||||
keywords: { $seen: true },
|
||||
size: 2100,
|
||||
receivedAt: demoDate(-1, -4),
|
||||
from: [{ name: 'Demo User', email: 'demo@example.com' }],
|
||||
to: [{ name: 'Alice Johnson', email: 'alice.johnson@example.com' }],
|
||||
subject: 'Updated Requirements Document',
|
||||
sentAt: demoDate(-1, -4),
|
||||
preview: 'Hi Alice, I\'ve updated the requirements document with the changes we discussed...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-11', size: 290, type: 'text/plain' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Hi Alice,\n\nI\'ve updated the requirements document with the changes we discussed in yesterday\'s meeting. The main updates are in sections 3 and 5.\n\nLet me know if you have any questions.\n\nBest,\nDemo User' },
|
||||
},
|
||||
messageId: '<sent-1@example.com>',
|
||||
},
|
||||
{
|
||||
id: 'demo-email-7',
|
||||
threadId: 'demo-thread-7',
|
||||
mailboxIds: { 'demo-mailbox-sent': true },
|
||||
keywords: { $seen: true },
|
||||
size: 1800,
|
||||
receivedAt: demoDate(-4, -2),
|
||||
from: [{ name: 'Demo User', email: 'demo@example.com' }],
|
||||
to: [{ name: 'Sarah Kim', email: 'sarah.kim@example.com' }],
|
||||
subject: 'Re: Design Feedback',
|
||||
sentAt: demoDate(-4, -2),
|
||||
preview: 'Thanks Sarah! The new color scheme looks great. I especially like the contrast improvements...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-12', size: 250, type: 'text/plain' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Thanks Sarah! The new color scheme looks great. I especially like the contrast improvements for accessibility.\n\nLet\'s go with Option B for the navigation.\n\nBest,\nDemo User' },
|
||||
},
|
||||
messageId: '<sent-2@example.com>',
|
||||
},
|
||||
|
||||
// ── Drafts ──────────────────────────────────────────────────
|
||||
{
|
||||
id: 'demo-email-8',
|
||||
threadId: 'demo-thread-8',
|
||||
mailboxIds: { 'demo-mailbox-drafts': true },
|
||||
keywords: { $seen: true, $draft: true },
|
||||
size: 900,
|
||||
receivedAt: demoDate(0, -1),
|
||||
from: [{ name: 'Demo User', email: 'demo@example.com' }],
|
||||
to: [{ name: 'Bob Chen', email: 'bob.chen@example.com' }],
|
||||
subject: 'Meeting Notes - Draft',
|
||||
sentAt: demoDate(0, -1),
|
||||
preview: 'Here are the notes from today\'s standup...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-13', size: 180, type: 'text/plain' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Here are the notes from today\'s standup:\n\n- API integration on track\n- Need to resolve the caching issue\n- ' },
|
||||
},
|
||||
messageId: '<draft-1@example.com>',
|
||||
},
|
||||
|
||||
// ── Trash ───────────────────────────────────────────────────
|
||||
{
|
||||
id: 'demo-email-9',
|
||||
threadId: 'demo-thread-9',
|
||||
mailboxIds: { 'demo-mailbox-trash': true },
|
||||
keywords: { $seen: true },
|
||||
size: 15200,
|
||||
receivedAt: demoDate(-5, -3),
|
||||
from: [{ name: 'Promo Store', email: 'deals@promostore.example' }],
|
||||
to: [{ name: 'Demo User', email: 'demo@example.com' }],
|
||||
subject: '🎉 Flash Sale: 50% Off Everything!',
|
||||
sentAt: demoDate(-5, -3),
|
||||
preview: 'Limited time offer! Get 50% off all items in our store...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-14', size: 400, type: 'text/plain' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Limited time offer! Get 50% off all items in our store. Use code FLASH50 at checkout.' },
|
||||
},
|
||||
messageId: '<promo-1@promostore.example>',
|
||||
},
|
||||
{
|
||||
id: 'demo-email-10',
|
||||
threadId: 'demo-thread-10',
|
||||
mailboxIds: { 'demo-mailbox-trash': true },
|
||||
keywords: { $seen: true },
|
||||
size: 2300,
|
||||
receivedAt: demoDate(-7, 0),
|
||||
from: [{ name: 'System Notification', email: 'noreply@service.example' }],
|
||||
to: [{ name: 'Demo User', email: 'demo@example.com' }],
|
||||
subject: 'Your password was changed',
|
||||
sentAt: demoDate(-7, 0),
|
||||
preview: 'Your account password was successfully changed on...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-15', size: 200, type: 'text/plain' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Your account password was successfully changed. If you did not make this change, please contact support immediately.' },
|
||||
},
|
||||
messageId: '<notification-1@service.example>',
|
||||
},
|
||||
|
||||
// ── Projects ────────────────────────────────────────────────
|
||||
{
|
||||
id: 'demo-email-11',
|
||||
threadId: 'demo-thread-11',
|
||||
mailboxIds: { 'demo-mailbox-projects': true },
|
||||
keywords: { $seen: true, $flagged: true },
|
||||
size: 4500,
|
||||
receivedAt: demoDate(-2, -7),
|
||||
from: [{ name: 'Alice Johnson', email: 'alice.johnson@example.com' }],
|
||||
to: [{ name: 'Demo User', email: 'demo@example.com' }],
|
||||
subject: '[Project] Sprint Planning Agenda',
|
||||
sentAt: demoDate(-2, -7),
|
||||
preview: 'Here\'s the agenda for next week\'s sprint planning session...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-16', size: 600, type: 'text/plain' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Hi team,\n\nHere\'s the agenda for next week\'s sprint planning:\n\n1. Review previous sprint velocity\n2. Discuss tech debt items\n3. Prioritize backlog\n4. Assign story points\n5. Capacity planning\n\nPlease come prepared with your updates.\n\nThanks,\nAlice' },
|
||||
},
|
||||
messageId: '<project-1@example.com>',
|
||||
},
|
||||
{
|
||||
id: 'demo-email-12',
|
||||
threadId: 'demo-thread-12',
|
||||
mailboxIds: { 'demo-mailbox-projects': true },
|
||||
keywords: {},
|
||||
size: 3200,
|
||||
receivedAt: demoDate(0, -8),
|
||||
from: [{ name: 'Bob Chen', email: 'bob.chen@example.com' }],
|
||||
to: [{ name: 'Demo User', email: 'demo@example.com' }],
|
||||
subject: '[Project] API Rate Limiting Discussion',
|
||||
sentAt: demoDate(0, -8),
|
||||
preview: 'I\'ve been thinking about our rate limiting approach and wanted to propose a few changes...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-17', size: 480, type: 'text/plain' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Hey,\n\nI\'ve been thinking about our rate limiting approach and wanted to propose:\n\n1. Token bucket algorithm instead of fixed window\n2. Per-endpoint limits rather than global\n3. Graduated response (warn → throttle → block)\n\nThoughts? I can put together a more detailed RFC if we agree on the direction.\n\n— Bob' },
|
||||
},
|
||||
messageId: '<project-2@example.com>',
|
||||
},
|
||||
|
||||
// ── Archive ─────────────────────────────────────────────────
|
||||
{
|
||||
id: 'demo-email-13',
|
||||
threadId: 'demo-thread-13',
|
||||
mailboxIds: { 'demo-mailbox-archive': true },
|
||||
keywords: { $seen: true },
|
||||
size: 2600,
|
||||
receivedAt: demoDate(-14, -6),
|
||||
from: [{ name: 'HR Department', email: 'hr@company.example' }],
|
||||
to: [{ name: 'Demo User', email: 'demo@example.com' }],
|
||||
subject: 'Updated PTO Policy - Effective January 1',
|
||||
sentAt: demoDate(-14, -6),
|
||||
preview: 'Please review the updated PTO policy that takes effect January 1st...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-18', size: 380, type: 'text/plain' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Dear team,\n\nPlease review the updated PTO policy effective January 1st. Key changes include:\n\n- Increased annual allowance from 20 to 25 days\n- Flexible half-day options\n- Rollover limit increased to 10 days\n\nPlease acknowledge receipt.\n\nBest,\nHR Department' },
|
||||
},
|
||||
messageId: '<hr-policy-1@company.example>',
|
||||
},
|
||||
|
||||
// ── Receipts ────────────────────────────────────────────────
|
||||
{
|
||||
id: 'demo-email-14',
|
||||
threadId: 'demo-thread-14',
|
||||
mailboxIds: { 'demo-mailbox-receipts': true },
|
||||
keywords: { $seen: true },
|
||||
size: 5200,
|
||||
receivedAt: demoDate(-3, -12),
|
||||
from: [{ name: 'Cloud Services', email: 'billing@cloudprovider.example' }],
|
||||
to: [{ name: 'Demo User', email: 'demo@example.com' }],
|
||||
subject: 'Payment Receipt - Invoice #INV-2024-1042',
|
||||
sentAt: demoDate(-3, -12),
|
||||
preview: 'Your payment of $49.99 has been processed successfully...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-19', size: 350, type: 'text/plain' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Payment Confirmation\n\nAmount: $49.99\nDate: Processing date\nInvoice: INV-2024-1042\nService: Cloud Hosting (Standard Plan)\n\nThank you for your payment.' },
|
||||
},
|
||||
messageId: '<receipt-1@cloudprovider.example>',
|
||||
},
|
||||
|
||||
// ── Spam ────────────────────────────────────────────────────
|
||||
{
|
||||
id: 'demo-email-15',
|
||||
threadId: 'demo-thread-15',
|
||||
mailboxIds: { 'demo-mailbox-junk': true },
|
||||
keywords: {},
|
||||
size: 8900,
|
||||
receivedAt: demoDate(-1, -9),
|
||||
from: [{ name: 'Prize Center', email: 'winner@totallylegit.example' }],
|
||||
to: [{ name: 'Demo User', email: 'demo@example.com' }],
|
||||
subject: 'Congratulations! You Won $1,000,000!!!',
|
||||
sentAt: demoDate(-1, -9),
|
||||
preview: 'Dear lucky winner, you have been selected to receive one million dollars...',
|
||||
hasAttachment: false,
|
||||
textBody: [{ partId: '1', blobId: 'blob-20', size: 500, type: 'text/plain' }],
|
||||
bodyValues: {
|
||||
'1': { value: 'Dear lucky winner,\n\nYou have been selected to receive ONE MILLION DOLLARS! Click below to claim your prize immediately.\n\n[This is a demo spam email]' },
|
||||
},
|
||||
messageId: '<spam-1@totallylegit.example>',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import type { FileNode } from '@/lib/jmap/types';
|
||||
import { demoDate } from '../demo-utils';
|
||||
|
||||
export function createDemoFileNodes(): FileNode[] {
|
||||
return [
|
||||
// Root-level directories
|
||||
{
|
||||
id: 'demo-file-documents',
|
||||
parentId: null,
|
||||
name: 'Documents',
|
||||
type: 'd',
|
||||
blobId: null,
|
||||
size: 0,
|
||||
created: demoDate(-30),
|
||||
updated: demoDate(-2),
|
||||
},
|
||||
{
|
||||
id: 'demo-file-photos',
|
||||
parentId: null,
|
||||
name: 'Photos',
|
||||
type: 'd',
|
||||
blobId: null,
|
||||
size: 0,
|
||||
created: demoDate(-30),
|
||||
updated: demoDate(-5),
|
||||
},
|
||||
|
||||
// Documents contents
|
||||
{
|
||||
id: 'demo-file-meeting-notes',
|
||||
parentId: 'demo-file-documents',
|
||||
name: 'meeting-notes.md',
|
||||
type: 'text/markdown',
|
||||
blobId: 'demo-blob-file-1',
|
||||
size: 2150,
|
||||
created: demoDate(-7),
|
||||
updated: demoDate(-2),
|
||||
},
|
||||
{
|
||||
id: 'demo-file-quarterly-report',
|
||||
parentId: 'demo-file-documents',
|
||||
name: 'quarterly-report.pdf',
|
||||
type: 'application/pdf',
|
||||
blobId: 'demo-blob-file-2',
|
||||
size: 148480,
|
||||
created: demoDate(-14),
|
||||
updated: demoDate(-14),
|
||||
},
|
||||
{
|
||||
id: 'demo-file-todo',
|
||||
parentId: 'demo-file-documents',
|
||||
name: 'todo.txt',
|
||||
type: 'text/plain',
|
||||
blobId: 'demo-blob-file-3',
|
||||
size: 410,
|
||||
created: demoDate(-3),
|
||||
updated: demoDate(-1),
|
||||
},
|
||||
|
||||
// Photos contents
|
||||
{
|
||||
id: 'demo-file-vacation',
|
||||
parentId: 'demo-file-photos',
|
||||
name: 'vacation.jpg',
|
||||
type: 'image/jpeg',
|
||||
blobId: 'demo-blob-file-4',
|
||||
size: 1258291,
|
||||
created: demoDate(-10),
|
||||
updated: demoDate(-10),
|
||||
},
|
||||
{
|
||||
id: 'demo-file-team-photo',
|
||||
parentId: 'demo-file-photos',
|
||||
name: 'team-photo.png',
|
||||
type: 'image/png',
|
||||
blobId: 'demo-blob-file-5',
|
||||
size: 911360,
|
||||
created: demoDate(-21),
|
||||
updated: demoDate(-21),
|
||||
},
|
||||
|
||||
// Root-level file
|
||||
{
|
||||
id: 'demo-file-budget',
|
||||
parentId: null,
|
||||
name: 'budget.xlsx',
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
blobId: 'demo-blob-file-6',
|
||||
size: 68608,
|
||||
created: demoDate(-5),
|
||||
updated: demoDate(-1),
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import type { SieveScript, SieveCapabilities } from '@/lib/jmap/sieve-types';
|
||||
|
||||
export function createDemoSieveCapabilities(): SieveCapabilities {
|
||||
return {
|
||||
implementation: 'Demo Sieve Engine',
|
||||
maxSizeScript: 65536,
|
||||
sieveExtensions: ['fileinto', 'reject', 'vacation', 'imap4flags', 'comparator-i;ascii-casemap', 'body', 'envelope'],
|
||||
notificationMethods: [],
|
||||
externalLists: [],
|
||||
};
|
||||
}
|
||||
|
||||
export function createDemoSieveScripts(): SieveScript[] {
|
||||
return [
|
||||
{
|
||||
id: 'demo-sieve-1',
|
||||
name: 'Default Filters',
|
||||
blobId: 'demo-sieve-blob-1',
|
||||
isActive: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
// Sieve script content keyed by blobId
|
||||
export function createDemoSieveContent(): Record<string, string> {
|
||||
return {
|
||||
'demo-sieve-blob-1': [
|
||||
'require ["fileinto", "imap4flags"];',
|
||||
'',
|
||||
'# Newsletters to Receipts',
|
||||
'if address :contains "from" "newsletter@" {',
|
||||
' fileinto "Receipts";',
|
||||
' stop;',
|
||||
'}',
|
||||
'',
|
||||
'# Flag emails from boss',
|
||||
'if address :is "from" "alice.johnson@example.com" {',
|
||||
' addflag "\\\\Flagged";',
|
||||
'}',
|
||||
'',
|
||||
'# Move project updates',
|
||||
'if header :contains "subject" "[Project]" {',
|
||||
' fileinto "Projects";',
|
||||
' stop;',
|
||||
'}',
|
||||
].join('\n'),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import type { Identity } from '@/lib/jmap/types';
|
||||
|
||||
export function createDemoIdentities(): Identity[] {
|
||||
return [
|
||||
{
|
||||
id: 'demo-identity-primary',
|
||||
name: 'Demo User',
|
||||
email: 'demo@example.com',
|
||||
textSignature: 'Best regards,\nDemo User\nBulwark Mail Demo',
|
||||
htmlSignature: '<p>Best regards,<br><b>Demo User</b><br>Bulwark Mail Demo</p>',
|
||||
mayDelete: false,
|
||||
},
|
||||
{
|
||||
id: 'demo-identity-alias',
|
||||
name: 'Demo User',
|
||||
email: 'demo+newsletter@example.com',
|
||||
textSignature: '',
|
||||
htmlSignature: '',
|
||||
mayDelete: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { Mailbox } from '@/lib/jmap/types';
|
||||
|
||||
const RIGHTS_SYSTEM = { mayReadItems: true, mayAddItems: true, mayRemoveItems: true, maySetSeen: true, maySetKeywords: true, mayCreateChild: true, mayRename: false, mayDelete: false, maySubmit: true };
|
||||
const RIGHTS_CUSTOM = { ...RIGHTS_SYSTEM, mayRename: true, mayDelete: true };
|
||||
|
||||
export function createDemoMailboxes(): Mailbox[] {
|
||||
return [
|
||||
{ id: 'demo-mailbox-inbox', name: 'Inbox', role: 'inbox', sortOrder: 1, totalEmails: 12, unreadEmails: 5, totalThreads: 10, unreadThreads: 4, myRights: RIGHTS_SYSTEM, isSubscribed: true },
|
||||
{ id: 'demo-mailbox-sent', name: 'Sent', role: 'sent', sortOrder: 2, totalEmails: 8, unreadEmails: 0, totalThreads: 8, unreadThreads: 0, myRights: RIGHTS_SYSTEM, isSubscribed: true },
|
||||
{ id: 'demo-mailbox-drafts', name: 'Drafts', role: 'drafts', sortOrder: 3, totalEmails: 1, unreadEmails: 0, totalThreads: 1, unreadThreads: 0, myRights: RIGHTS_SYSTEM, isSubscribed: true },
|
||||
{ id: 'demo-mailbox-trash', name: 'Trash', role: 'trash', sortOrder: 5, totalEmails: 2, unreadEmails: 0, totalThreads: 2, unreadThreads: 0, myRights: RIGHTS_SYSTEM, isSubscribed: true },
|
||||
{ id: 'demo-mailbox-archive', name: 'Archive', role: 'archive', sortOrder: 4, totalEmails: 4, unreadEmails: 0, totalThreads: 4, unreadThreads: 0, myRights: RIGHTS_SYSTEM, isSubscribed: true },
|
||||
{ id: 'demo-mailbox-junk', name: 'Spam', role: 'junk', sortOrder: 6, totalEmails: 3, unreadEmails: 1, totalThreads: 3, unreadThreads: 1, myRights: RIGHTS_SYSTEM, isSubscribed: true },
|
||||
{ id: 'demo-mailbox-projects', name: 'Projects', sortOrder: 10, totalEmails: 5, unreadEmails: 2, totalThreads: 5, unreadThreads: 2, myRights: RIGHTS_CUSTOM, isSubscribed: true },
|
||||
{ id: 'demo-mailbox-receipts', name: 'Receipts', sortOrder: 11, totalEmails: 3, unreadEmails: 0, totalThreads: 3, unreadThreads: 0, myRights: RIGHTS_CUSTOM, isSubscribed: true },
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { VacationResponse } from '@/lib/jmap/types';
|
||||
|
||||
export function createDemoVacationResponse(): VacationResponse {
|
||||
return {
|
||||
id: 'singleton',
|
||||
isEnabled: false,
|
||||
fromDate: null,
|
||||
toDate: null,
|
||||
subject: 'Out of Office',
|
||||
textBody: 'Thank you for your email. I am currently out of the office and will return on Monday. For urgent matters, please contact support@example.com.',
|
||||
htmlBody: '<p>Thank you for your email. I am currently out of the office and will return on Monday.</p><p>For urgent matters, please contact <a href="mailto:support@example.com">support@example.com</a>.</p>',
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user