diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 2aa659a..7bab3aa 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -1,1185 +1,1088 @@ 'use client'; -import { useState, useEffect } from 'react'; +import { useState, useEffect, useRef, useCallback } from 'react'; -// Types -type Image = { - id: number; - data: string; - filename: string; - category: string; - room_id: number | null; - location_target: string; +type Image = { id: number; filename: string; data: string; category: string; room_id: number | null; location_target: string; uploaded_at: string }; +type Slide = { id: number; title: string; subtitle: string; image_url: string | null; image_id: number | null; active: boolean; sort_order: number }; +type Room = { id: number; name: string; description: string; price: string; photos: string[]; featured_photo: string | null; active: boolean; sort_order: number }; +type CalendarEvent = { id: number; date: string; title: string; type: string; color: string; description: string | null; active: boolean }; +type SocialEvent = { id: number; name: string; description: string; price: string | null; date: string | null; photos: string[]; featured_photo: string | null; active: boolean; sort_order: number }; +type MenuItem = { id: number; category: string; name: string; description: string; price: string; is_daily_special: boolean; active: boolean; sort_order: number }; +type Place = { id: number; name: string; description: string; photos: string[]; featured_photo: string | null; distance_km: string; visit_time: string; suggestion: string; active: boolean; sort_order: number }; +type Review = { id: number; author_name: string; author_email: string | null; rating: number; text: string; approved: boolean }; +type FooterConfig = { logo: string; favicon: string; tagline: string; facebook_url: string; instagram_url: string; whatsapp_url: string; address: string; phone: string; email: string }; +type SocialRes = { id: number; event_id: number; username: string; event_name: string; guests: number; notes: string; status: string; created_at: string }; + +const C = { + gold: '#D4A853', goldLight: 'rgba(212,168,83,0.12)', navy: '#010D1E', + warm: '#7A5A3A', bg: '#F7F4EF', card: '#FFFFFF', border: 'rgba(1,13,30,0.08)', + text: '#444444', textLight: '#888888', danger: '#D32F2F', success: '#388E3C', + shadow: '0 1px 4px rgba(1,13,30,0.06)', shadowHover: '0 6px 20px rgba(1,13,30,0.12)', }; -type FooterInfo = { - facebook_url: string; - instagram_url: string; - whatsapp_url: string; - address: string; - phone: string; - email: string; -}; +const NAV = [ + { id: 'brand', label: 'Brand', icon: '🎨' }, + { id: 'gallery', label: 'Images', icon: 'πŸ–ΌοΈ' }, + { id: 'slides', label: 'Slideshow', icon: '🎞️' }, + { id: 'calendar', label: 'Calendar', icon: 'πŸ“…' }, + { id: 'social', label: 'Social Events', icon: 'πŸŽͺ' }, + { id: 'rooms', label: 'Rooms', icon: '🏨' }, + { id: 'menu', label: 'Menu', icon: '🍽️' }, + { id: 'places', label: 'Places', icon: 'πŸ—ΊοΈ' }, + { id: 'reviews', label: 'Reviews', icon: '⭐' }, + { id: 'users', label: 'Users', icon: 'πŸ‘₯' }, +]; -type Slide = { - id: number; - title: string; - subtitle: string; - image_id: number | null; - image_url: string; - active: boolean; - sort_order: number; -}; - -type CalendarEvent = { - id: number; - date: string; - title: string; - type: 'holiday' | 'season' | 'weather' | 'event'; - color: string; - description: string; - active: boolean; -}; - -type SocialEvent = { - id: number; - name: string; - description: string; - price: string; - date: string; - photos: string[]; - featured_photo: string | null; - active: boolean; - sort_order: number; - reservation_count: number; -}; - -type SocialEventReservation = { - id: number; - event_id: number; - username: string; - event_name: string; - guests: number; - notes: string; - status: 'pending' | 'confirmed' | 'cancelled'; - created_at: string; -}; - -type Room = { - id: number; - name: string; - description: string; - price: string; - photos: string[]; - featured_photo: string | null; - active: boolean; - sort_order: number; -}; - -type RoomComment = { - id: number; - room_id: number; - first_name: string; - last_initial: string; - text: string; - created_at: string; -}; - -type MenuItem = { - id: number; - category: string; - name: string; - description: string; - price: string; - is_daily_special: boolean; - active: boolean; - sort_order: number; -}; - -type Place = { - id: number; - name: string; - description: string; - photos: string[]; - featured_photo: string | null; - distance_km: string; - visit_time: string; - suggestion: string; - active: boolean; - sort_order: number; -}; - -type Review = { - id: number; - author_name: string; - rating: number; - text: string; - approved: boolean; -}; - -// Constants -const gold = '#E8A849'; -const navy = '#010D1E'; -const warm = '#7A5A3A'; - -// Components -function Text({ label, value, onChange, type = 'text' }: { label: string; value: string; onChange: (value: string) => void; type?: string }) { +function I({ label, value, onChange, type = 'text', placeholder, style }: any) { return ( - +
+ {label && } + onChange(e.target.value)} placeholder={placeholder} + style={{ padding: '8px 12px', borderRadius: 8, border: `1px solid ${C.border}`, fontSize: '14px', outline: 'none', background: '#FAFAFA', ...style }} + onFocus={e => { e.target.style.borderColor = C.gold; e.target.style.background = C.white; }} + onBlur={e => { e.target.style.borderColor = C.border; e.target.style.background = '#FAFAFA'; }} /> +
); } -function Number({ label, value, onChange }: { label: string; value: number; onChange: (value: string) => void }) { +function TA({ label, value, onChange, rows = 3 }: any) { return ( - +
+ {label && } +