Some checks are pending
E2E / Playwright e2e (push) Waiting to run
- Introduced turbopack alias for canvas in next.config.mjs. - Updated package.json scripts for development and branding tasks. - Added new dependencies for Tiptap extensions. - Implemented new demo layouts for agenda, contacts, drive, and mail applications. - Enhanced globals.css for improved theming and splash screen animations. - Added OAuth callback handling for drive mounts. - Updated layout components to integrate new demo shells and improve structure.
109 lines
2.9 KiB
TypeScript
109 lines
2.9 KiB
TypeScript
"use client"
|
|
|
|
import { create } from "zustand"
|
|
import { fullContactToApiContact } from "@/lib/api/adapters"
|
|
import type { ApiContact } from "@/lib/api/types"
|
|
import { DEMO_FULL_CONTACTS } from "@/components/demo/demo-contacts-data"
|
|
import type { FullContact } from "@/lib/contacts/types"
|
|
import { rankApiContacts } from "@/lib/contacts/contact-match-score"
|
|
|
|
const DEMO_BOOK_ID = "contacts"
|
|
|
|
function toDemoContact(full: FullContact): ApiContact {
|
|
const partial = fullContactToApiContact(full)
|
|
return {
|
|
uid: full.id,
|
|
full_name: partial.full_name ?? "Contact",
|
|
email: partial.email,
|
|
phone: partial.phone,
|
|
org: partial.org,
|
|
path: `books/${DEMO_BOOK_ID}/${full.id}.vcf`,
|
|
etag: `"demo-${full.id}"`,
|
|
raw_vcard: partial.raw_vcard,
|
|
}
|
|
}
|
|
|
|
function createInitialContacts(): ApiContact[] {
|
|
return DEMO_FULL_CONTACTS.map(toDemoContact)
|
|
}
|
|
|
|
type DemoContactsStoreState = {
|
|
active: boolean
|
|
contacts: ApiContact[]
|
|
version: number
|
|
}
|
|
|
|
type DemoContactsStoreActions = {
|
|
reset: () => void
|
|
bump: () => void
|
|
listBooks: () => { id: string; name: string }[]
|
|
listContacts: (bookId: string) => ApiContact[]
|
|
searchContacts: (query: string) => ApiContact[]
|
|
createContact: (bookId: string, contact: Partial<ApiContact>) => ApiContact
|
|
updateContact: (path: string, contact: Partial<ApiContact>) => void
|
|
deleteContact: (path: string) => void
|
|
}
|
|
|
|
export const useDemoContactsStore = create<
|
|
DemoContactsStoreState & DemoContactsStoreActions
|
|
>( (set, get) => ({
|
|
active: false,
|
|
contacts: [],
|
|
version: 0,
|
|
|
|
reset: () =>
|
|
set({
|
|
active: true,
|
|
contacts: createInitialContacts(),
|
|
version: get().version + 1,
|
|
}),
|
|
|
|
bump: () => set({ version: get().version + 1 }),
|
|
|
|
listBooks: () => [{ id: DEMO_BOOK_ID, name: "Contacts" }],
|
|
|
|
listContacts: (bookId) => {
|
|
if (bookId !== DEMO_BOOK_ID) return []
|
|
return get().contacts
|
|
},
|
|
|
|
searchContacts: (query) => rankApiContacts(get().contacts, query),
|
|
|
|
createContact: (bookId, contact) => {
|
|
const uid = contact.uid ?? `demo-contact-${crypto.randomUUID().slice(0, 8)}`
|
|
const created: ApiContact = {
|
|
uid,
|
|
full_name: contact.full_name ?? "Contact",
|
|
email: contact.email,
|
|
phone: contact.phone,
|
|
org: contact.org,
|
|
path: `books/${bookId}/${uid}.vcf`,
|
|
etag: `"demo-${uid}"`,
|
|
raw_vcard: contact.raw_vcard,
|
|
}
|
|
set((state) => ({
|
|
contacts: [...state.contacts, created],
|
|
version: state.version + 1,
|
|
}))
|
|
return created
|
|
},
|
|
|
|
updateContact: (path, contact) => {
|
|
set((state) => ({
|
|
contacts: state.contacts.map((c) =>
|
|
c.path === path || c.uid === path
|
|
? { ...c, ...contact, path: c.path, uid: c.uid, etag: `"demo-${c.uid}-v2"` }
|
|
: c
|
|
),
|
|
version: state.version + 1,
|
|
}))
|
|
},
|
|
|
|
deleteContact: (path) => {
|
|
set((state) => ({
|
|
contacts: state.contacts.filter((c) => c.path !== path && c.uid !== path),
|
|
version: state.version + 1,
|
|
}))
|
|
},
|
|
}))
|