Initial commit
This commit is contained in:
127
src/lib/assessmentShareService.js
Normal file
127
src/lib/assessmentShareService.js
Normal file
@@ -0,0 +1,127 @@
|
||||
import { calculateExercise } from '../utils/patCalculations'
|
||||
import { supabase } from './supabaseClient'
|
||||
|
||||
const hydrateExercise = (exercise = {}) => {
|
||||
const normalized = {
|
||||
name: exercise.name || '',
|
||||
soll: exercise.soll ?? 0,
|
||||
faktor: exercise.faktor ?? 0
|
||||
}
|
||||
|
||||
if (exercise.subA && exercise.subB) {
|
||||
normalized.subA = exercise.subA
|
||||
normalized.subB = exercise.subB
|
||||
if (exercise.subLabels) {
|
||||
normalized.subLabels = exercise.subLabels
|
||||
}
|
||||
} else {
|
||||
normalized.values = exercise.values || []
|
||||
}
|
||||
|
||||
const { durchschnitt, points } = calculateExercise({
|
||||
...normalized,
|
||||
values: normalized.values || []
|
||||
})
|
||||
|
||||
return {
|
||||
...normalized,
|
||||
durchschnitt,
|
||||
points
|
||||
}
|
||||
}
|
||||
|
||||
const mapSharedAssessment = (row) => ({
|
||||
id: row.id,
|
||||
patType: row.pat_type,
|
||||
datum: row.datum,
|
||||
name: row.name,
|
||||
exercises: (row.exercises || []).map(hydrateExercise)
|
||||
})
|
||||
|
||||
const getSingleRow = (data) => (Array.isArray(data) ? data[0] || null : data || null)
|
||||
|
||||
const buildShareUrl = (shareToken) => {
|
||||
if (typeof window === 'undefined') {
|
||||
return `?share=${shareToken}`
|
||||
}
|
||||
|
||||
const url = new URL(window.location.origin + window.location.pathname)
|
||||
url.searchParams.set('share', shareToken)
|
||||
return url.toString()
|
||||
}
|
||||
|
||||
export const createAssessmentShareLink = async (assessment) => {
|
||||
if (!assessment) {
|
||||
throw new Error('Kein Test zum Teilen gefunden.')
|
||||
}
|
||||
|
||||
if (!supabase) {
|
||||
throw new Error('Supabase ist nicht konfiguriert.')
|
||||
}
|
||||
|
||||
const { data, error } = await supabase.rpc('create_or_get_assessment_share', {
|
||||
p_assessment_id: assessment.id
|
||||
})
|
||||
|
||||
if (error) throw error
|
||||
|
||||
const row = getSingleRow(data)
|
||||
if (!row?.share_token) {
|
||||
throw new Error('Kein Freigabetoken erhalten.')
|
||||
}
|
||||
|
||||
return {
|
||||
token: row.share_token,
|
||||
url: buildShareUrl(row.share_token)
|
||||
}
|
||||
}
|
||||
|
||||
export const listAssessmentShares = async (assessmentIds = []) => {
|
||||
if (!supabase) {
|
||||
throw new Error('Supabase ist nicht konfiguriert.')
|
||||
}
|
||||
|
||||
if (!assessmentIds.length) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('assessment_shares')
|
||||
.select('assessment_id, share_token')
|
||||
.in('assessment_id', assessmentIds)
|
||||
|
||||
if (error) throw error
|
||||
|
||||
return (data || []).reduce((acc, row) => {
|
||||
acc[row.assessment_id] = row.share_token
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
|
||||
export const revokeAssessmentShare = async (assessmentId) => {
|
||||
if (!supabase) {
|
||||
throw new Error('Supabase ist nicht konfiguriert.')
|
||||
}
|
||||
|
||||
const { error } = await supabase
|
||||
.from('assessment_shares')
|
||||
.delete()
|
||||
.eq('assessment_id', assessmentId)
|
||||
|
||||
if (error) throw error
|
||||
}
|
||||
|
||||
export const getSharedAssessment = async (shareToken) => {
|
||||
if (!supabase) {
|
||||
throw new Error('Supabase ist nicht konfiguriert.')
|
||||
}
|
||||
|
||||
const { data, error } = await supabase.rpc('get_shared_assessment', {
|
||||
p_share_token: shareToken
|
||||
})
|
||||
|
||||
if (error) throw error
|
||||
|
||||
const row = getSingleRow(data)
|
||||
return row ? mapSharedAssessment(row) : null
|
||||
}
|
||||
12
src/lib/supabaseClient.js
Normal file
12
src/lib/supabaseClient.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
|
||||
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY
|
||||
|
||||
if (!supabaseUrl || !supabaseAnonKey) {
|
||||
console.warn('Supabase env vars missing. Auth is disabled until VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY are set.')
|
||||
}
|
||||
|
||||
export const supabase = supabaseUrl && supabaseAnonKey
|
||||
? createClient(supabaseUrl, supabaseAnonKey)
|
||||
: null
|
||||
66
src/lib/trainingPlanService.js
Normal file
66
src/lib/trainingPlanService.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import { supabase } from './supabaseClient';
|
||||
|
||||
const normalizeTasks = (tasks) => {
|
||||
if (!Array.isArray(tasks)) return [];
|
||||
return tasks.map((task) => ({
|
||||
type: task?.type || 'task',
|
||||
title: task?.title || '',
|
||||
durationMin: Number(task?.durationMin || 0),
|
||||
repetitions: task?.repetitions ?? null,
|
||||
intensity: task?.intensity || null,
|
||||
instructions: task?.instructions || ''
|
||||
}));
|
||||
};
|
||||
|
||||
export const mapSessionToRpc = (session) => ({
|
||||
weekNo: Number(session?.weekNo || session?.week_no || 1),
|
||||
sessionNo: Number(session?.sessionNo || session?.session_no || 1),
|
||||
mainExercise: session?.mainExercise || session?.main_exercise || 'Basistechnik',
|
||||
secondaryExercises: Array.isArray(session?.secondaryExercises)
|
||||
? session.secondaryExercises
|
||||
: Array.isArray(session?.secondary_exercises)
|
||||
? session.secondary_exercises
|
||||
: [],
|
||||
tasks: normalizeTasks(session?.tasks),
|
||||
state: session?.state || 'open',
|
||||
notes: session?.notes || ''
|
||||
});
|
||||
|
||||
export const saveTrainingPlanWithSessions = async ({
|
||||
patType,
|
||||
analysisSnapshot,
|
||||
durationWeeks,
|
||||
sessionsPerWeek,
|
||||
sessions
|
||||
}) => {
|
||||
if (!supabase) {
|
||||
return {
|
||||
ok: false,
|
||||
error: new Error('Supabase ist nicht konfiguriert.')
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const payload = {
|
||||
p_pat_type: patType,
|
||||
p_analysis_snapshot: analysisSnapshot,
|
||||
p_duration_weeks: Number(durationWeeks),
|
||||
p_sessions_per_week: Number(sessionsPerWeek),
|
||||
p_sessions: (sessions || []).map(mapSessionToRpc)
|
||||
};
|
||||
|
||||
const { data, error } = await supabase.rpc('create_training_plan_with_sessions', payload);
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
planId: data
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
ok: false,
|
||||
error
|
||||
};
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user