| |
|
|
| import { supabase } from './supabase'; |
| import type { |
| ApprovalType as DbApprovalType, |
| ApprovalStatus as DbApprovalStatus, |
| } from './database.types'; |
|
|
| export type ApprovalType = DbApprovalType; |
| export type ApprovalStatus = DbApprovalStatus; |
|
|
| |
| export interface ApprovalItem { |
| id: string; |
| type: ApprovalType; |
| status: ApprovalStatus; |
| requesterId: string | null; |
| requesterName: string; |
| title: string; |
| description: string | null; |
| payload: Record<string, unknown>; |
| reviewerId?: string | null; |
| reviewerName?: string | null; |
| reviewedAt?: string | null; |
| rejectReason?: string | null; |
| createdAt: string; |
| } |
|
|
| export interface ApprovalFilters { |
| type?: ApprovalType; |
| status?: ApprovalStatus; |
| requesterId?: string; |
| } |
|
|
| export interface ApprovalStats { |
| pending: number; |
| approved: number; |
| rejected: number; |
| byType: Record<ApprovalType, number>; |
| } |
|
|
| |
|
|
| function dbToItem(row: Record<string, unknown>): ApprovalItem { |
| return { |
| id: row.id as string, |
| type: row.type as ApprovalType, |
| status: row.status as ApprovalStatus, |
| requesterId: (row.requester_id as string) ?? null, |
| requesterName: row.requester_name as string, |
| title: row.title as string, |
| description: (row.description as string) ?? null, |
| payload: (row.payload as Record<string, unknown>) ?? {}, |
| reviewerId: (row.reviewer_id as string) ?? null, |
| reviewerName: (row.reviewer_name as string) ?? null, |
| reviewedAt: (row.reviewed_at as string) ?? null, |
| rejectReason: (row.reject_reason as string) ?? null, |
| createdAt: row.created_at as string, |
| }; |
| } |
|
|
| |
|
|
| export async function getApprovalQueue(filters?: ApprovalFilters): Promise<ApprovalItem[]> { |
| let query = supabase |
| .from('approval_queue') |
| .select('*') |
| .order('created_at', { ascending: false }); |
|
|
| if (filters?.type) query = query.eq('type', filters.type); |
| if (filters?.status) query = query.eq('status', filters.status); |
| if (filters?.requesterId) query = query.eq('requester_id', filters.requesterId); |
|
|
| const { data, error } = await query; |
| if (error) { |
| console.error('getApprovalQueue error:', error); |
| return []; |
| } |
| return (data ?? []).map(dbToItem); |
| } |
|
|
| export async function getApprovalById(id: string): Promise<ApprovalItem | undefined> { |
| const { data, error } = await supabase |
| .from('approval_queue') |
| .select('*') |
| .eq('id', id) |
| .maybeSingle(); |
|
|
| if (error) { |
| console.error('getApprovalById error:', error); |
| return undefined; |
| } |
| return data ? dbToItem(data) : undefined; |
| } |
|
|
| export async function createApproval( |
| item: Omit<ApprovalItem, 'id' | 'createdAt'>, |
| ): Promise<ApprovalItem | null> { |
| const row = { |
| type: item.type, |
| status: item.status, |
| requester_id: item.requesterId, |
| requester_name: item.requesterName, |
| title: item.title, |
| description: item.description, |
| payload: item.payload, |
| reviewer_id: item.reviewerId ?? null, |
| reviewer_name: item.reviewerName ?? null, |
| reviewed_at: item.reviewedAt ?? null, |
| reject_reason: item.rejectReason ?? null, |
| }; |
|
|
| const { data, error } = await supabase |
| .from('approval_queue') |
| .insert(row) |
| .select() |
| .single(); |
|
|
| if (error) { |
| console.error('createApproval error:', error); |
| return null; |
| } |
| return dbToItem(data); |
| } |
|
|
| export async function updateApprovalStatus( |
| id: string, |
| status: ApprovalStatus, |
| reviewerId?: string, |
| reviewerName?: string, |
| rejectReason?: string, |
| ): Promise<ApprovalItem | null> { |
| const updates: Record<string, unknown> = { |
| status, |
| reviewer_id: reviewerId ?? null, |
| reviewer_name: reviewerName ?? null, |
| reviewed_at: new Date().toISOString(), |
| }; |
| if (status === 'rejected' && rejectReason) { |
| updates.reject_reason = rejectReason; |
| } |
|
|
| const { data, error } = await supabase |
| .from('approval_queue') |
| .update(updates) |
| .eq('id', id) |
| .select() |
| .single(); |
|
|
| if (error) { |
| console.error('updateApprovalStatus error:', error); |
| return null; |
| } |
| return dbToItem(data); |
| } |
|
|
| export async function getApprovalsByRequester(requesterId: string): Promise<ApprovalItem[]> { |
| return getApprovalQueue({ requesterId }); |
| } |
|
|
| export async function getApprovalStats(): Promise<ApprovalStats> { |
| const { data, error } = await supabase |
| .from('approval_queue') |
| .select('type, status'); |
|
|
| if (error) { |
| console.error('getApprovalStats error:', error); |
| return { |
| pending: 0, approved: 0, rejected: 0, |
| byType: { |
| campaign_review: 0, sme_application: 0, sme_selection: 0, |
| trade_request: 0, point_conversion: 0, finance_registration: 0, |
| }, |
| }; |
| } |
|
|
| const items = (data ?? []) as { type: ApprovalType; status: ApprovalStatus }[]; |
| const allTypes: ApprovalType[] = [ |
| 'campaign_review', 'sme_application', 'sme_selection', |
| 'trade_request', 'point_conversion', 'finance_registration', |
| ]; |
| const byType = Object.fromEntries( |
| allTypes.map((t) => [t, items.filter((i) => i.type === t && i.status === 'pending').length]), |
| ) as Record<ApprovalType, number>; |
|
|
| return { |
| pending: items.filter((i) => i.status === 'pending').length, |
| approved: items.filter((i) => i.status === 'approved').length, |
| rejected: items.filter((i) => i.status === 'rejected').length, |
| byType, |
| }; |
| } |
|
|
| |
|
|
| export const approvalTypeLabels: Record<ApprovalType, string> = { |
| campaign_review: '์บ ํ์ธ ์น์ธ', |
| sme_application: 'SME ์ํ ์ ์ฒญ', |
| sme_selection: 'SME ์ ์ ', |
| trade_request: '๊ฑฐ๋ ์น์ธ', |
| point_conversion: 'ํฌ์ธํธ ์ ํ', |
| finance_registration: '๊ธ์ต์ฌ ๊ฐ์
', |
| }; |
|
|
| export const approvalStatusLabels: Record<ApprovalStatus, string> = { |
| pending: '๋๊ธฐ', |
| approved: '์น์ธ', |
| rejected: '๋ฐ๋ ค', |
| cancelled: '์ทจ์', |
| }; |
|
|