refactor: generate and use Supabase TypeScript types
Co-authored-by: Moheeb Zara <[email protected]>
This commit is contained in:
@@ -3,16 +3,20 @@
|
|||||||
import { useState, useEffect, useRef } from 'react'
|
import { useState, useEffect, useRef } from 'react'
|
||||||
import { createClient } from '@/lib/supabase/client'
|
import { createClient } from '@/lib/supabase/client'
|
||||||
import { Hash, Users2, Send, ChevronLeft } from 'lucide-react'
|
import { Hash, Users2, Send, ChevronLeft } from 'lucide-react'
|
||||||
|
import type { Tables } from '@/types/database'
|
||||||
|
|
||||||
|
type Channel = Tables<'comms_channels'>
|
||||||
|
type Message = Tables<'comms_messages'>
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
member: any
|
member: Tables<'space_members'>
|
||||||
space: any
|
space: Tables<'spaces'>
|
||||||
channels: any[]
|
channels: Channel[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CommsClient({ member, space, channels }: Props) {
|
export default function CommsClient({ member, space, channels }: Props) {
|
||||||
const [selectedChannel, setSelectedChannel] = useState(channels[0] || null)
|
const [selectedChannel, setSelectedChannel] = useState<Channel | null>(channels[0] || null)
|
||||||
const [messages, setMessages] = useState<any[]>([])
|
const [messages, setMessages] = useState<Message[]>([])
|
||||||
const [newMessage, setNewMessage] = useState('')
|
const [newMessage, setNewMessage] = useState('')
|
||||||
const [sending, setSending] = useState(false)
|
const [sending, setSending] = useState(false)
|
||||||
const [showChannelList, setShowChannelList] = useState(true)
|
const [showChannelList, setShowChannelList] = useState(true)
|
||||||
|
|||||||
@@ -3,19 +3,9 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Plus, X, Pencil } from 'lucide-react'
|
import { Plus, X, Pencil } from 'lucide-react'
|
||||||
import { createContact, updateContact, deleteContact } from '@/lib/actions'
|
import { createContact, updateContact, deleteContact } from '@/lib/actions'
|
||||||
|
import type { Tables } from '@/types/database'
|
||||||
|
|
||||||
interface Contact {
|
type Contact = Tables<'contacts'>
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
contact_type: string
|
|
||||||
email?: string
|
|
||||||
phone?: string
|
|
||||||
details?: string
|
|
||||||
note?: string
|
|
||||||
group_label?: string
|
|
||||||
tags?: string[]
|
|
||||||
code?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const CATEGORY_COLORS: Record<string, string> = {
|
const CATEGORY_COLORS: Record<string, string> = {
|
||||||
vendor: 'text-primary border-primary/30 bg-primary/5',
|
vendor: 'text-primary border-primary/30 bg-primary/5',
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { createClient } from '@/lib/supabase/server'
|
import { createClient } from '@/lib/supabase/server'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { redirect } from 'next/navigation'
|
import { redirect } from 'next/navigation'
|
||||||
|
import type { Tables } from '@/types/database'
|
||||||
|
|
||||||
function IcoUsers({ className }: { className?: string }) {
|
function IcoUsers({ className }: { className?: string }) {
|
||||||
return <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" /></svg>
|
return <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" /></svg>
|
||||||
@@ -50,7 +51,7 @@ export default async function DashboardPage() {
|
|||||||
supabase.from('activity_log').select('*').eq('space_id', spaceId).order('created_at', { ascending: false }).limit(6),
|
supabase.from('activity_log').select('*').eq('space_id', spaceId).order('created_at', { ascending: false }).limit(6),
|
||||||
])
|
])
|
||||||
|
|
||||||
const overdueTasks = (tasks ?? []).filter((t: any) => t.due_date && new Date(t.due_date) < new Date())
|
const overdueTasks = (tasks ?? []).filter((t) => t.due_date && new Date(t.due_date) < new Date())
|
||||||
|
|
||||||
const stats = [
|
const stats = [
|
||||||
{ label: 'Active Members', value: activeMembers ?? 0, Ico: IcoUsers, sub: 'in your space', warn: false },
|
{ label: 'Active Members', value: activeMembers ?? 0, Ico: IcoUsers, sub: 'in your space', warn: false },
|
||||||
@@ -91,7 +92,7 @@ export default async function DashboardPage() {
|
|||||||
<Link href="/tasks" className="font-sans text-xs text-primary hover:underline">All tasks</Link>
|
<Link href="/tasks" className="font-sans text-xs text-primary hover:underline">All tasks</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-card rounded border border-border divide-y divide-border">
|
<div className="bg-card rounded border border-border divide-y divide-border">
|
||||||
{(tasks ?? []).length > 0 ? (tasks ?? []).map((task: any) => {
|
{(tasks ?? []).length > 0 ? (tasks ?? []).map((task) => {
|
||||||
const isOverdue = task.due_date && new Date(task.due_date) < new Date()
|
const isOverdue = task.due_date && new Date(task.due_date) < new Date()
|
||||||
const isDueToday = task.due_date && new Date(task.due_date).toDateString() === new Date().toDateString()
|
const isDueToday = task.due_date && new Date(task.due_date).toDateString() === new Date().toDateString()
|
||||||
return (
|
return (
|
||||||
@@ -127,7 +128,7 @@ export default async function DashboardPage() {
|
|||||||
<Link href="/projects" className="font-sans text-xs text-primary hover:underline">All projects</Link>
|
<Link href="/projects" className="font-sans text-xs text-primary hover:underline">All projects</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-card rounded border border-border divide-y divide-border">
|
<div className="bg-card rounded border border-border divide-y divide-border">
|
||||||
{(projects ?? []).length > 0 ? (projects ?? []).map((project: any) => (
|
{(projects ?? []).length > 0 ? (projects ?? []).map((project) => (
|
||||||
<div key={project.id} className="px-4 py-4">
|
<div key={project.id} className="px-4 py-4">
|
||||||
<div className="flex items-center justify-between mb-1">
|
<div className="flex items-center justify-between mb-1">
|
||||||
<p className="font-sans text-sm font-medium text-foreground">{project.title}</p>
|
<p className="font-sans text-sm font-medium text-foreground">{project.title}</p>
|
||||||
@@ -167,7 +168,7 @@ export default async function DashboardPage() {
|
|||||||
<div>
|
<div>
|
||||||
<p className="font-mono text-[10px] tracking-widest text-muted-foreground uppercase mb-3">Recent Activity</p>
|
<p className="font-mono text-[10px] tracking-widest text-muted-foreground uppercase mb-3">Recent Activity</p>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{(activity ?? []).length > 0 ? (activity ?? []).map((item: any) => (
|
{(activity ?? []).length > 0 ? (activity ?? []).map((item) => (
|
||||||
<div key={item.id} className="flex items-start gap-2.5">
|
<div key={item.id} className="flex items-start gap-2.5">
|
||||||
<div className="w-1.5 h-1.5 rounded-full mt-2 flex-shrink-0 bg-primary" />
|
<div className="w-1.5 h-1.5 rounded-full mt-2 flex-shrink-0 bg-primary" />
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -246,13 +246,22 @@ export default function ImportClient({ spaceId, role }: Props) {
|
|||||||
const last_paid_at = obj.last_paid_at ? new Date(obj.last_paid_at).toISOString() : null
|
const last_paid_at = obj.last_paid_at ? new Date(obj.last_paid_at).toISOString() : null
|
||||||
const has_card_access = /yes|true|1|y/i.test(obj.has_card_access ?? '')
|
const has_card_access = /yes|true|1|y/i.test(obj.has_card_access ?? '')
|
||||||
|
|
||||||
|
// Map tier value to valid enum or default to 'basic'
|
||||||
|
const tierMap: Record<string, 'plus' | 'basic' | 'associate'> = {
|
||||||
|
plus: 'plus', premium: 'plus', full: 'plus',
|
||||||
|
basic: 'basic', member: 'basic', standard: 'basic',
|
||||||
|
associate: 'associate', visitor: 'associate', guest: 'associate',
|
||||||
|
}
|
||||||
|
const tier = tierMap[(obj.tier || '').toLowerCase()] || 'basic'
|
||||||
|
|
||||||
const { error } = await supabase.from('space_members').insert({
|
const { error } = await supabase.from('space_members').insert({
|
||||||
space_id: spaceId,
|
space_id: spaceId,
|
||||||
|
user_id: crypto.randomUUID(),
|
||||||
display_name: obj.display_name,
|
display_name: obj.display_name,
|
||||||
email: obj.email,
|
email: obj.email,
|
||||||
phone: obj.phone || null,
|
phone: obj.phone || null,
|
||||||
handle: obj.handle || null,
|
handle: obj.handle || null,
|
||||||
tier: obj.tier || 'member',
|
tier,
|
||||||
role: 'member',
|
role: 'member',
|
||||||
status: 'current',
|
status: 'current',
|
||||||
approved: true,
|
approved: true,
|
||||||
|
|||||||
@@ -3,24 +3,9 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Plus, X, ChevronDown } from 'lucide-react'
|
import { Plus, X, ChevronDown } from 'lucide-react'
|
||||||
import { addMember, updateMember, approveMember, removeMember } from '@/lib/actions'
|
import { addMember, updateMember, approveMember, removeMember } from '@/lib/actions'
|
||||||
|
import type { Tables } from '@/types/database'
|
||||||
|
|
||||||
interface Member {
|
type Member = Tables<'space_members'>
|
||||||
id: string
|
|
||||||
display_name: string
|
|
||||||
email: string
|
|
||||||
phone?: string
|
|
||||||
handle?: string
|
|
||||||
tier: string
|
|
||||||
role: string
|
|
||||||
status: string
|
|
||||||
joined_at?: string
|
|
||||||
last_paid_at?: string
|
|
||||||
last_payment_at?: string
|
|
||||||
payment_status?: string
|
|
||||||
payment_note?: string
|
|
||||||
has_card_access?: boolean
|
|
||||||
approved?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
members: Member[]
|
members: Member[]
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ import Link from 'next/link'
|
|||||||
import { ArrowLeft, Pin, Lock } from 'lucide-react'
|
import { ArrowLeft, Pin, Lock } from 'lucide-react'
|
||||||
import { createKbEntry, updateKbEntry } from '@/lib/actions'
|
import { createKbEntry, updateKbEntry } from '@/lib/actions'
|
||||||
import { toast } from 'sonner'
|
import { toast } from 'sonner'
|
||||||
|
import type { Tables } from '@/types/database'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
entry?: any
|
entry?: Tables<'knowledge_base'>
|
||||||
member: any
|
member: Tables<'space_members'>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function KbEntryEditor({ entry, member }: Props) {
|
export default function KbEntryEditor({ entry, member }: Props) {
|
||||||
|
|||||||
@@ -6,39 +6,14 @@ import { Plus, Search, Lock, Pin, Eye, EyeOff, Pencil, Trash2, X, ChevronDown, U
|
|||||||
import { createKbEntry, updateKbEntry, deleteKbEntry } from '@/lib/actions'
|
import { createKbEntry, updateKbEntry, deleteKbEntry } from '@/lib/actions'
|
||||||
import { createClient } from '@/lib/supabase/client'
|
import { createClient } from '@/lib/supabase/client'
|
||||||
import { toast } from 'sonner'
|
import { toast } from 'sonner'
|
||||||
|
import type { Tables, TablesInsert } from '@/types/database'
|
||||||
|
|
||||||
interface KbEntry {
|
type KbEntry = Tables<'knowledge_base'>
|
||||||
id: string
|
type AreaLead = Tables<'area_leads'>
|
||||||
title: string
|
type Secret = Tables<'secrets'>
|
||||||
content: string
|
|
||||||
description?: string
|
|
||||||
area?: string
|
|
||||||
visibility: string
|
|
||||||
is_pinned: boolean
|
|
||||||
tags?: string[]
|
|
||||||
icon?: string
|
|
||||||
updated_by_name?: string
|
|
||||||
updated_at: string
|
|
||||||
created_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AreaLead {
|
|
||||||
id: string
|
|
||||||
area_name: string
|
|
||||||
lead_handle: string
|
|
||||||
lead_id?: string
|
|
||||||
description?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Secret {
|
|
||||||
id: string
|
|
||||||
title: string
|
|
||||||
area?: string
|
|
||||||
created_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
member: any
|
member: Tables<'space_members'>
|
||||||
spaceId: string
|
spaceId: string
|
||||||
kbEntries: KbEntry[]
|
kbEntries: KbEntry[]
|
||||||
areaLeads: AreaLead[]
|
areaLeads: AreaLead[]
|
||||||
|
|||||||
@@ -4,21 +4,14 @@ import { useState } from 'react'
|
|||||||
import { X, RefreshCcw } from 'lucide-react'
|
import { X, RefreshCcw } from 'lucide-react'
|
||||||
import { toast } from 'sonner'
|
import { toast } from 'sonner'
|
||||||
import { logCashPayment, linkPaymentToMember } from '@/lib/actions'
|
import { logCashPayment, linkPaymentToMember } from '@/lib/actions'
|
||||||
|
import type { Tables } from '@/types/database'
|
||||||
|
|
||||||
interface Payment {
|
type Payment = Tables<'payments'> & {
|
||||||
id: string
|
|
||||||
platform: string
|
|
||||||
amount: number
|
|
||||||
from_identifier: string
|
|
||||||
from_note?: string
|
|
||||||
transaction_date: string
|
|
||||||
link_status: string
|
|
||||||
member_id?: string
|
|
||||||
space_members?: { display_name: string } | null
|
space_members?: { display_name: string } | null
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Member { id: string; display_name: string; email: string }
|
type Member = Pick<Tables<'space_members'>, 'id' | 'display_name' | 'email'>
|
||||||
interface Integration { platform: string; is_connected: boolean; config?: Record<string, string> }
|
type Integration = Pick<Tables<'integrations'>, 'platform' | 'is_connected' | 'config'>
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
payments: Payment[]
|
payments: Payment[]
|
||||||
|
|||||||
@@ -3,18 +3,9 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Plus, X } from 'lucide-react'
|
import { Plus, X } from 'lucide-react'
|
||||||
import { createProject, updateProjectStatus, deleteProject } from '@/lib/actions'
|
import { createProject, updateProjectStatus, deleteProject } from '@/lib/actions'
|
||||||
|
import type { Tables } from '@/types/database'
|
||||||
|
|
||||||
interface Project {
|
type Project = Tables<'projects'>
|
||||||
id: string
|
|
||||||
title: string
|
|
||||||
description?: string
|
|
||||||
status: string
|
|
||||||
area?: string
|
|
||||||
tags?: string[]
|
|
||||||
progress?: number
|
|
||||||
due_date?: string
|
|
||||||
created_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const STATUS_COLS = [
|
const STATUS_COLS = [
|
||||||
{ key: 'backlog', label: 'BACKLOG', color: 'text-muted-foreground', dot: 'bg-muted-foreground' },
|
{ key: 'backlog', label: 'BACKLOG', color: 'text-muted-foreground', dot: 'bg-muted-foreground' },
|
||||||
|
|||||||
@@ -3,25 +3,10 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { X, Check, Copy, Eye, EyeOff, RotateCcw } from 'lucide-react'
|
import { X, Check, Copy, Eye, EyeOff, RotateCcw } from 'lucide-react'
|
||||||
import { updateSpaceSettings, saveIntegration, disconnectIntegration, rotateWebhookSecret } from '@/lib/actions'
|
import { updateSpaceSettings, saveIntegration, disconnectIntegration, rotateWebhookSecret } from '@/lib/actions'
|
||||||
|
import type { Tables } from '@/types/database'
|
||||||
|
|
||||||
interface Space {
|
type Space = Tables<'spaces'>
|
||||||
id: string
|
type Integration = Tables<'integrations'>
|
||||||
name: string
|
|
||||||
slug: string
|
|
||||||
city?: string
|
|
||||||
invite_code?: string
|
|
||||||
require_approval?: boolean
|
|
||||||
public_member_directory?: boolean
|
|
||||||
webhook_secret?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Integration {
|
|
||||||
id: string
|
|
||||||
platform: string
|
|
||||||
name?: string
|
|
||||||
is_connected: boolean
|
|
||||||
config?: Record<string, string>
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
space: Space
|
space: Space
|
||||||
|
|||||||
@@ -3,30 +3,13 @@
|
|||||||
import { useState, useTransition } from 'react'
|
import { useState, useTransition } from 'react'
|
||||||
import { Plus, X, CheckCircle2 } from 'lucide-react'
|
import { Plus, X, CheckCircle2 } from 'lucide-react'
|
||||||
import { createTask, claimTask, completeTask, deleteTask } from '@/lib/actions'
|
import { createTask, claimTask, completeTask, deleteTask } from '@/lib/actions'
|
||||||
|
import type { Tables } from '@/types/database'
|
||||||
|
|
||||||
interface Task {
|
type Task = Tables<'tasks'>
|
||||||
id: string
|
|
||||||
title: string
|
|
||||||
description?: string
|
|
||||||
type?: string
|
|
||||||
task_type?: string
|
|
||||||
status: string
|
|
||||||
area?: string
|
|
||||||
recurrence?: string
|
|
||||||
due_date?: string
|
|
||||||
claimed_by?: string
|
|
||||||
claimed_by_name?: string
|
|
||||||
assigned_to?: string
|
|
||||||
assigned_to_name?: string
|
|
||||||
progress?: number
|
|
||||||
subtask_completed?: number
|
|
||||||
subtask_total?: number
|
|
||||||
created_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
tasks: Task[]
|
tasks: Task[]
|
||||||
members: { id: string; display_name: string; user_id: string }[]
|
members: Pick<Tables<'space_members'>, 'id' | 'display_name' | 'user_id'>[]
|
||||||
currentUserId: string
|
currentUserId: string
|
||||||
spaceId: string
|
spaceId: string
|
||||||
}
|
}
|
||||||
@@ -57,8 +40,8 @@ export function TasksClient({ tasks: initialTasks, members, currentUserId, space
|
|||||||
// Chores = chore type OR regular tasks without recurrence (the general open pool)
|
// Chores = chore type OR regular tasks without recurrence (the general open pool)
|
||||||
// Mine = tasks claimed/assigned to me
|
// Mine = tasks claimed/assigned to me
|
||||||
// Done = completed
|
// Done = completed
|
||||||
const isDone = (t: any) => t.status === 'done' || t.status === 'completed'
|
const isDone = (t: Task) => t.status === 'done' || t.status === 'completed'
|
||||||
const isOpen = (t: any) => !isDone(t)
|
const isOpen = (t: Task) => !isDone(t)
|
||||||
const chores = tasks.filter(t => isOpen(t) && (!t.recurrence || t.recurrence === 'none'))
|
const chores = tasks.filter(t => isOpen(t) && (!t.recurrence || t.recurrence === 'none'))
|
||||||
const ongoing = tasks.filter(t => t.recurrence && t.recurrence !== 'none' && isOpen(t))
|
const ongoing = tasks.filter(t => t.recurrence && t.recurrence !== 'none' && isOpen(t))
|
||||||
const mine = tasks.filter(t => (t.claimed_by === currentUserId || t.assigned_to === currentUserId) && isOpen(t))
|
const mine = tasks.filter(t => (t.claimed_by === currentUserId || t.assigned_to === currentUserId) && isOpen(t))
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
LayoutDashboard, ListChecks, FolderKanban, Settings2, MessageSquare,
|
LayoutDashboard, ListChecks, FolderKanban, Settings2, MessageSquare,
|
||||||
Users, CreditCard, BookUser, Download, LogOut, ChevronDown
|
Users, CreditCard, BookUser, Download, LogOut, ChevronDown
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
|
import type { Tables } from '@/types/database'
|
||||||
|
|
||||||
const NAV = [
|
const NAV = [
|
||||||
{
|
{
|
||||||
@@ -38,8 +39,8 @@ const NAV = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
member: any
|
member: Tables<'space_members'>
|
||||||
space: any
|
space: Tables<'spaces'>
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -3,6 +3,8 @@
|
|||||||
import { createClient } from '@/lib/supabase/server'
|
import { createClient } from '@/lib/supabase/server'
|
||||||
import { redirect } from 'next/navigation'
|
import { redirect } from 'next/navigation'
|
||||||
import { revalidatePath } from 'next/cache'
|
import { revalidatePath } from 'next/cache'
|
||||||
|
import type { SupabaseClient } from '@supabase/supabase-js'
|
||||||
|
import type { Database } from '@/types/database'
|
||||||
|
|
||||||
// ─── Auth ────────────────────────────────────────────────────────────────────
|
// ─── Auth ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -26,7 +28,7 @@ export async function getUser() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ─── Helper: get current member (any non-inactive status) ────────────────────
|
// ─── Helper: get current member (any non-inactive status) ────────────────────
|
||||||
async function getMember(supabase: any, userId: string) {
|
async function getMember(supabase: SupabaseClient<Database>, userId: string) {
|
||||||
const { data } = await supabase
|
const { data } = await supabase
|
||||||
.from('space_members')
|
.from('space_members')
|
||||||
.select('space_id, role, display_name')
|
.select('space_id, role, display_name')
|
||||||
@@ -670,6 +672,7 @@ export async function createSecret(formData: {
|
|||||||
const { data, error } = await supabase.from('secrets').insert({
|
const { data, error } = await supabase.from('secrets').insert({
|
||||||
space_id: member.space_id,
|
space_id: member.space_id,
|
||||||
title: formData.title,
|
title: formData.title,
|
||||||
|
label: formData.title,
|
||||||
value: formData.value,
|
value: formData.value,
|
||||||
description: formData.description,
|
description: formData.description,
|
||||||
area: formData.area,
|
area: formData.area,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { createClient } from '@supabase/supabase-js'
|
import { createClient } from '@supabase/supabase-js'
|
||||||
|
import type { Database } from '@/types/database'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Admin client using the service role key.
|
* Admin client using the service role key.
|
||||||
@@ -6,7 +7,7 @@ import { createClient } from '@supabase/supabase-js'
|
|||||||
* NEVER expose this client to the browser.
|
* NEVER expose this client to the browser.
|
||||||
*/
|
*/
|
||||||
export function createAdminClient() {
|
export function createAdminClient() {
|
||||||
return createClient(
|
return createClient<Database>(
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||||
process.env.SUPABASE_SERVICE_ROLE_KEY!,
|
process.env.SUPABASE_SERVICE_ROLE_KEY!,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { createBrowserClient } from '@supabase/ssr'
|
import { createBrowserClient } from '@supabase/ssr'
|
||||||
|
import type { Database } from '@/types/database'
|
||||||
|
|
||||||
export function createClient() {
|
export function createClient() {
|
||||||
return createBrowserClient(
|
return createBrowserClient<Database>(
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { createServerClient } from '@supabase/ssr'
|
import { createServerClient } from '@supabase/ssr'
|
||||||
import { cookies } from 'next/headers'
|
import { cookies } from 'next/headers'
|
||||||
|
import type { Database } from '@/types/database'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Especially important if using Fluid compute: Don't put this client in a
|
* Especially important if using Fluid compute: Don't put this client in a
|
||||||
@@ -9,7 +10,7 @@ import { cookies } from 'next/headers'
|
|||||||
export async function createClient() {
|
export async function createClient() {
|
||||||
const cookieStore = await cookies()
|
const cookieStore = await cookies()
|
||||||
|
|
||||||
return createServerClient(
|
return createServerClient<Database>(
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||||
{
|
{
|
||||||
|
|||||||
+35
-203
@@ -1,206 +1,38 @@
|
|||||||
// Enum values match live DB exactly
|
/**
|
||||||
export type MemberTier = 'plus' | 'basic' | 'associate'
|
* Re-export types from the generated database types.
|
||||||
export type MemberRole = 'admin' | 'board' | 'treasurer' | 'member' | 'associate'
|
* These types are auto-generated from the Supabase schema.
|
||||||
export type MemberStatus = 'current' | 'late' | 'inactive' | 'unverified'
|
*
|
||||||
export type TaskType = 'chore' | 'task'
|
* To regenerate: Use the supabase_generate_typescript_types tool
|
||||||
export type TaskStatus = 'open' | 'claimed' | 'in_progress' | 'overdue' | 'due_today' | 'completed' | 'done' | 'blocked'
|
*/
|
||||||
export type TaskRecurrence = 'none' | 'daily' | 'weekly' | 'biweekly' | 'monthly'
|
|
||||||
export type ProjectStatus = 'backlog' | 'in_progress' | 'review' | 'done' | 'blocked'
|
|
||||||
export type KBVisibility = 'all_members' | 'board' | 'admin_only'
|
|
||||||
export type ContactType = 'vendor' | 'supplier' | 'partner' | 'landlord' | 'city'
|
|
||||||
export type PaymentPlatform = 'paypal' | 'zeffy' | 'venmo' | 'cash'
|
|
||||||
export type PaymentLinkStatus = 'linked' | 'unlinked'
|
|
||||||
export type ChannelType = 'general' | 'area' | 'ops' | 'project'
|
|
||||||
export type AreaLeadStatus = 'active' | 'vacant' | 'handoff'
|
|
||||||
|
|
||||||
export interface Space {
|
import type { Tables, Enums } from '@/types/database'
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
slug: string
|
|
||||||
city?: string
|
|
||||||
invite_code: string
|
|
||||||
require_approval: boolean
|
|
||||||
public_member_directory: boolean
|
|
||||||
webhook_secret?: string
|
|
||||||
created_at: string
|
|
||||||
updated_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SpaceMember {
|
// ─── Table Row Types ───────────────────────────────────────────────────────────
|
||||||
id: string
|
export type Space = Tables<'spaces'>
|
||||||
space_id: string
|
export type SpaceMember = Tables<'space_members'>
|
||||||
user_id: string
|
export type Task = Tables<'tasks'>
|
||||||
display_name: string
|
export type Project = Tables<'projects'>
|
||||||
handle?: string
|
export type KnowledgeBase = Tables<'knowledge_base'>
|
||||||
email?: string
|
export type Secret = Tables<'secrets'>
|
||||||
phone?: string
|
export type AreaLead = Tables<'area_leads'>
|
||||||
tier: MemberTier
|
export type Contact = Tables<'contacts'>
|
||||||
role: MemberRole
|
export type Payment = Tables<'payments'>
|
||||||
status: MemberStatus
|
export type CommsChannel = Tables<'comms_channels'>
|
||||||
joined_at: string
|
export type CommsMessage = Tables<'comms_messages'>
|
||||||
approved: boolean
|
export type Integration = Tables<'integrations'>
|
||||||
has_card_access: boolean
|
export type ActivityLog = Tables<'activity_log'>
|
||||||
last_payment_at?: string
|
|
||||||
last_paid_at?: string
|
|
||||||
payment_status?: string
|
|
||||||
payment_note?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Task {
|
// ─── Enum Types ────────────────────────────────────────────────────────────────
|
||||||
id: string
|
export type MemberTier = Enums<'member_tier'>
|
||||||
space_id: string
|
export type MemberRole = Enums<'member_role'>
|
||||||
task_type: TaskType
|
export type MemberStatus = Enums<'member_status'>
|
||||||
title: string
|
export type TaskType = Enums<'task_type'>
|
||||||
description?: string
|
export type TaskStatus = Enums<'task_status'>
|
||||||
status: TaskStatus
|
export type TaskRecurrence = Enums<'recurrence_type'>
|
||||||
area?: string
|
export type ProjectStatus = Enums<'project_status'>
|
||||||
assigned_to?: string
|
export type KBVisibility = Enums<'kb_visibility'>
|
||||||
assigned_to_name?: string
|
export type ContactType = Enums<'contact_type'>
|
||||||
claimed_by?: string
|
export type PaymentPlatform = Enums<'payment_platform'>
|
||||||
claimed_by_name?: string
|
export type PaymentLinkStatus = Enums<'payment_link_status'>
|
||||||
requested_by?: string
|
export type ChannelType = Enums<'channel_type'>
|
||||||
requested_by_name?: string
|
export type AreaLeadStatus = Enums<'area_lead_status'>
|
||||||
due_date?: string
|
|
||||||
recurrence: TaskRecurrence
|
|
||||||
last_done_at?: string
|
|
||||||
subtask_completed?: number
|
|
||||||
subtask_total?: number
|
|
||||||
completed_at?: string
|
|
||||||
created_at: string
|
|
||||||
updated_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Project {
|
|
||||||
id: string
|
|
||||||
space_id: string
|
|
||||||
title: string
|
|
||||||
description?: string
|
|
||||||
status: ProjectStatus
|
|
||||||
area?: string
|
|
||||||
tags?: string[]
|
|
||||||
assignee_names?: string[]
|
|
||||||
task_count?: number
|
|
||||||
tasks_completed?: number
|
|
||||||
due_date?: string
|
|
||||||
created_at: string
|
|
||||||
updated_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface KnowledgeBase {
|
|
||||||
id: string
|
|
||||||
space_id: string
|
|
||||||
title: string
|
|
||||||
content?: string
|
|
||||||
description?: string
|
|
||||||
area?: string
|
|
||||||
tags?: string[]
|
|
||||||
visibility: KBVisibility
|
|
||||||
access_level?: string
|
|
||||||
is_pinned: boolean
|
|
||||||
pinned?: boolean
|
|
||||||
icon?: string
|
|
||||||
updated_by_id?: string
|
|
||||||
updated_by_name?: string
|
|
||||||
updated_by?: string
|
|
||||||
created_at: string
|
|
||||||
updated_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Secret {
|
|
||||||
id: string
|
|
||||||
space_id: string
|
|
||||||
title: string
|
|
||||||
description?: string
|
|
||||||
value: string
|
|
||||||
area?: string
|
|
||||||
icon?: string
|
|
||||||
created_at: string
|
|
||||||
updated_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AreaLead {
|
|
||||||
id: string
|
|
||||||
space_id: string
|
|
||||||
area_code: string
|
|
||||||
area_name: string
|
|
||||||
lead_id?: string
|
|
||||||
lead_handle?: string
|
|
||||||
status: AreaLeadStatus
|
|
||||||
created_at: string
|
|
||||||
updated_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Contact {
|
|
||||||
id: string
|
|
||||||
space_id: string
|
|
||||||
contact_type: ContactType
|
|
||||||
code: string
|
|
||||||
name: string
|
|
||||||
email?: string
|
|
||||||
phone?: string
|
|
||||||
details?: string
|
|
||||||
tags?: string[]
|
|
||||||
created_at: string
|
|
||||||
updated_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Payment {
|
|
||||||
id: string
|
|
||||||
space_id: string
|
|
||||||
platform: PaymentPlatform
|
|
||||||
amount: number
|
|
||||||
from_identifier: string
|
|
||||||
from_note?: string
|
|
||||||
member_id?: string
|
|
||||||
member_name?: string
|
|
||||||
link_status: PaymentLinkStatus
|
|
||||||
transaction_date: string
|
|
||||||
created_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CommsChannel {
|
|
||||||
id: string
|
|
||||||
space_id: string
|
|
||||||
name: string
|
|
||||||
channel_type: ChannelType
|
|
||||||
icon?: string
|
|
||||||
area_reference?: string
|
|
||||||
project_id?: string
|
|
||||||
member_count?: number
|
|
||||||
created_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CommsMessage {
|
|
||||||
id: string
|
|
||||||
space_id: string
|
|
||||||
channel_id: string
|
|
||||||
user_id: string
|
|
||||||
display_name: string
|
|
||||||
handle?: string
|
|
||||||
content: string
|
|
||||||
created_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Integration {
|
|
||||||
id: string
|
|
||||||
space_id: string
|
|
||||||
platform: string
|
|
||||||
name: string
|
|
||||||
description?: string
|
|
||||||
is_connected: boolean
|
|
||||||
config?: any
|
|
||||||
created_at: string
|
|
||||||
updated_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ActivityLog {
|
|
||||||
id: string
|
|
||||||
space_id: string
|
|
||||||
user_id: string
|
|
||||||
display_name: string
|
|
||||||
action: string
|
|
||||||
entity_type: string
|
|
||||||
entity_id: string
|
|
||||||
details?: string
|
|
||||||
created_at: string
|
|
||||||
}
|
|
||||||
|
|||||||
+1037
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user