## Major Features - Apple Watch companion app (6 phases complete) - WatchConnectivity iPhone ↔ Watch - HealthKit integration (HR, calories) - SwiftUI premium UI - 9 complication types - Always-On Display support - Paywall screen with RevenueCat integration - Privacy Policy screen - App rebranding: tabatago → TabataFit - Bundle ID: com.millianlmx.tabatafit ## Changes - New: ios/TabataFit Watch App/ (complete Watch app) - New: app/paywall.tsx (subscription UI) - New: app/privacy.tsx (privacy policy) - New: src/features/watch/ (Watch sync hooks) - New: admin-web/ (admin dashboard) - Updated: app.json, package.json (branding) - Updated: profile.tsx (paywall + privacy links) - Updated: i18n translations (EN/FR/DE/ES) - New: app icon 1024x1024 ## Watch App Files - TabataFitWatchApp.swift (entry point) - ContentView.swift (premium UI) - HealthKitManager.swift (HR + calories) - WatchSessionManager.swift (communication) - Complications/ (WidgetKit) - UserDefaults+Shared.swift (data sharing)
184 lines
5.0 KiB
TypeScript
184 lines
5.0 KiB
TypeScript
/**
|
|
* TabataFit Seed Script
|
|
*
|
|
* This script seeds your Supabase database with the initial data.
|
|
* Run this after setting up your Supabase project.
|
|
*
|
|
* Usage:
|
|
* 1. Set your Supabase credentials in .env
|
|
* 2. Run: npx ts-node supabase/seed.ts
|
|
*/
|
|
|
|
import { createClient } from '@supabase/supabase-js'
|
|
import { WORKOUTS } from '../src/shared/data/workouts'
|
|
import { TRAINERS } from '../src/shared/data/trainers'
|
|
import { COLLECTIONS, PROGRAMS } from '../src/shared/data/collections'
|
|
import { ACHIEVEMENTS } from '../src/shared/data/achievements'
|
|
|
|
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL
|
|
const supabaseKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY
|
|
|
|
if (!supabaseUrl || !supabaseKey) {
|
|
console.error('Missing Supabase credentials. Please set EXPO_PUBLIC_SUPABASE_URL and EXPO_PUBLIC_SUPABASE_ANON_KEY')
|
|
process.exit(1)
|
|
}
|
|
|
|
const supabase = createClient(supabaseUrl, supabaseKey)
|
|
|
|
async function seedTrainers() {
|
|
console.log('Seeding trainers...')
|
|
|
|
const trainers = TRAINERS.map(t => ({
|
|
id: t.id,
|
|
name: t.name,
|
|
specialty: t.specialty,
|
|
color: t.color,
|
|
avatar_url: t.avatarUrl || null,
|
|
workout_count: t.workoutCount,
|
|
}))
|
|
|
|
const { error } = await supabase.from('trainers').upsert(trainers)
|
|
if (error) throw error
|
|
console.log(`✅ Seeded ${trainers.length} trainers`)
|
|
}
|
|
|
|
async function seedWorkouts() {
|
|
console.log('Seeding workouts...')
|
|
|
|
const workouts = WORKOUTS.map(w => ({
|
|
id: w.id,
|
|
title: w.title,
|
|
trainer_id: w.trainerId,
|
|
category: w.category,
|
|
level: w.level,
|
|
duration: w.duration,
|
|
calories: w.calories,
|
|
rounds: w.rounds,
|
|
prep_time: w.prepTime,
|
|
work_time: w.workTime,
|
|
rest_time: w.restTime,
|
|
equipment: w.equipment,
|
|
music_vibe: w.musicVibe,
|
|
exercises: w.exercises,
|
|
thumbnail_url: w.thumbnailUrl || null,
|
|
video_url: w.videoUrl || null,
|
|
is_featured: w.isFeatured || false,
|
|
}))
|
|
|
|
const { error } = await supabase.from('workouts').upsert(workouts)
|
|
if (error) throw error
|
|
console.log(`✅ Seeded ${workouts.length} workouts`)
|
|
}
|
|
|
|
async function seedCollections() {
|
|
console.log('Seeding collections...')
|
|
|
|
const collections = COLLECTIONS.map(c => ({
|
|
id: c.id,
|
|
title: c.title,
|
|
description: c.description,
|
|
icon: c.icon,
|
|
gradient: c.gradient || null,
|
|
}))
|
|
|
|
const { error } = await supabase.from('collections').upsert(collections)
|
|
if (error) throw error
|
|
|
|
// Seed collection-workout relationships
|
|
const collectionWorkouts = COLLECTIONS.flatMap(c =>
|
|
c.workoutIds.map((workoutId, index) => ({
|
|
collection_id: c.id,
|
|
workout_id: workoutId,
|
|
sort_order: index,
|
|
}))
|
|
)
|
|
|
|
const { error: linkError } = await supabase.from('collection_workouts').upsert(collectionWorkouts)
|
|
if (linkError) throw linkError
|
|
|
|
console.log(`✅ Seeded ${collections.length} collections with ${collectionWorkouts.length} workout links`)
|
|
}
|
|
|
|
async function seedPrograms() {
|
|
console.log('Seeding programs...')
|
|
|
|
const programs = PROGRAMS.map(p => ({
|
|
id: p.id,
|
|
title: p.title,
|
|
description: p.description,
|
|
weeks: p.weeks,
|
|
workouts_per_week: p.workoutsPerWeek,
|
|
level: p.level,
|
|
}))
|
|
|
|
const { error } = await supabase.from('programs').upsert(programs)
|
|
if (error) throw error
|
|
|
|
// Seed program-workout relationships
|
|
let programWorkouts: { program_id: string; workout_id: string; week_number: number; day_number: number }[] = []
|
|
|
|
PROGRAMS.forEach(program => {
|
|
let week = 1
|
|
let day = 1
|
|
program.workoutIds.forEach((workoutId, index) => {
|
|
programWorkouts.push({
|
|
program_id: program.id,
|
|
workout_id: workoutId,
|
|
week_number: week,
|
|
day_number: day,
|
|
})
|
|
day++
|
|
if (day > program.workoutsPerWeek) {
|
|
day = 1
|
|
week++
|
|
}
|
|
})
|
|
})
|
|
|
|
const { error: linkError } = await supabase.from('program_workouts').upsert(programWorkouts)
|
|
if (linkError) throw linkError
|
|
|
|
console.log(`✅ Seeded ${programs.length} programs with ${programWorkouts.length} workout links`)
|
|
}
|
|
|
|
async function seedAchievements() {
|
|
console.log('Seeding achievements...')
|
|
|
|
const achievements = ACHIEVEMENTS.map(a => ({
|
|
id: a.id,
|
|
title: a.title,
|
|
description: a.description,
|
|
icon: a.icon,
|
|
requirement: a.requirement,
|
|
type: a.type,
|
|
}))
|
|
|
|
const { error } = await supabase.from('achievements').upsert(achievements)
|
|
if (error) throw error
|
|
console.log(`✅ Seeded ${achievements.length} achievements`)
|
|
}
|
|
|
|
async function main() {
|
|
try {
|
|
console.log('🌱 Starting database seed...\n')
|
|
|
|
await seedTrainers()
|
|
await seedWorkouts()
|
|
await seedCollections()
|
|
await seedPrograms()
|
|
await seedAchievements()
|
|
|
|
console.log('\n✨ Database seeded successfully!')
|
|
console.log('\nNext steps:')
|
|
console.log('1. Set up storage buckets in Supabase Dashboard')
|
|
console.log('2. Upload video and thumbnail files')
|
|
console.log('3. Create an admin user in the admin_users table')
|
|
console.log('4. Access the admin dashboard at /admin')
|
|
} catch (error) {
|
|
console.error('\n❌ Seeding failed:', error)
|
|
process.exit(1)
|
|
}
|
|
}
|
|
|
|
main()
|