Admin dashboard: fix stats waterfall, redesign layout, add animations
Deploy to route.crispygoat.com / deploy (push) Failing after 3m13s
Deploy to route.crispygoat.com / deploy (push) Failing after 3m13s
- Fetch dashboard stats server-side in admin/page.tsx to eliminate client-side useEffect waterfall and the '—' placeholder flash - Pass pre-fetched stats as props to DashboardClient - Lazy-load UpgradePlanModal via next/dynamic (only loads when needed) - Redesign stats cards with compact layout, smaller icons, Fraunces serif values - Improve Quick Actions + Usage row: side-by-side on desktop, stacked mobile - Clean up Recent Orders as a proper list with icon/name/time/amount/badge - Add staggered fade-up entrance animations (0/60/120/180/240ms delays) - Consolidate loading.tsx skeleton to match actual dashboard structure - Mobile-responsive: 2-col stats on mobile, stacked usage, collapsible header
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
-- Migration 003: Batch insert RPCs for tour stop / location seeding
|
||||
-- Required by db/seeds/2026-tuxedo-tour-stops.sql and scripts/import-tuxedo-stops.ts
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- admin_create_locations_batch: insert or update locations from tour seed
|
||||
-- Payload shape: { name, address, city, state, zip, phone, contact_name, contact_email, notes, active }[]
|
||||
CREATE OR REPLACE FUNCTION admin_create_locations_batch(p_brand_id UUID, p_locations JSONB)
|
||||
RETURNS VOID LANGUAGE plpgsql SECURITY DEFINER AS $$
|
||||
DECLARE
|
||||
v_loc JSONB;
|
||||
BEGIN
|
||||
FOR v_loc IN SELECT * FROM jsonb_array_elements(p_locations)
|
||||
LOOP
|
||||
INSERT INTO locations (
|
||||
brand_id, name, address, city, state, zip,
|
||||
phone, contact_name, contact_email, notes, active
|
||||
) VALUES (
|
||||
p_brand_id,
|
||||
v_loc->>'name',
|
||||
v_loc->>'address',
|
||||
v_loc->>'city',
|
||||
v_loc->>'state',
|
||||
NULLIF(v_loc->>'zip', '')::TEXT,
|
||||
v_loc->>'phone',
|
||||
v_loc->>'contact_name',
|
||||
v_loc->>'contact_email',
|
||||
v_loc->>'notes',
|
||||
COALESCE((v_loc->>'active')::BOOLEAN, true)
|
||||
)
|
||||
ON CONFLICT DO NOTHING;
|
||||
END LOOP;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- admin_create_stops_batch: insert stops from tour seed
|
||||
-- Payload shape: { city, state, location, date, time, address, zip, cutoff_time, active, notes }[]
|
||||
-- date format: '2026-07-22 00:00:00+00' — cast to DATE
|
||||
CREATE OR REPLACE FUNCTION admin_create_stops_batch(p_brand_id UUID, p_stops JSONB)
|
||||
RETURNS VOID LANGUAGE plpgsql SECURITY DEFINER AS $$
|
||||
DECLARE
|
||||
v_stop JSONB;
|
||||
BEGIN
|
||||
FOR v_stop IN SELECT * FROM jsonb_array_elements(p_stops)
|
||||
LOOP
|
||||
INSERT INTO stops (
|
||||
brand_id, name, location, address, city, state, zip,
|
||||
date, "time", cutoff_date, status, is_public, notes
|
||||
) VALUES (
|
||||
p_brand_id,
|
||||
COALESCE(NULLIF(v_stop->>'name', ''), (v_stop->>'location')::TEXT || ' - ' || (v_stop->>'city')::TEXT || ', ' || (v_stop->>'state')::TEXT),
|
||||
v_stop->>'location',
|
||||
v_stop->>'address',
|
||||
v_stop->>'city',
|
||||
v_stop->>'state',
|
||||
NULLIF(v_stop->>'zip', '')::TEXT,
|
||||
CASE
|
||||
WHEN v_stop->>'date' IS NULL THEN NULL
|
||||
ELSE LEFT(v_stop->>'date', 10)::DATE
|
||||
END,
|
||||
v_stop->>'time',
|
||||
NULLIF(v_stop->>'cutoff_time', '')::DATE,
|
||||
'active',
|
||||
COALESCE((v_stop->>'active')::BOOLEAN, true),
|
||||
v_stop->>'notes'
|
||||
);
|
||||
END LOOP;
|
||||
END;
|
||||
$$;
|
||||
|
||||
COMMIT;
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user