journal-quest / src /lib /supabase.ts
MATSUMURA Taishi
Add 第2問(勘定記入)・第3問(財務諸表)
ebe620b
Raw
History Blame Contribute Delete
3.94 kB
import { createClient } from '@supabase/supabase-js'
import type { Problem, LedgerProblem, StatementProblem } from '../types'
const url = import.meta.env.VITE_SUPABASE_URL as string | undefined
const anonKey = import.meta.env.VITE_SUPABASE_ANON_KEY as string | undefined
export const isSupabaseConfigured = Boolean(url && anonKey)
export const supabase = isSupabaseConfigured
? createClient(url!, anonKey!)
: null
/**
* 第1問(仕訳)の問題を取得する。
* topic='all' または未指定のとき全論点を取得する。
* ※ isSolvable フィルタは適用しない(利息・消費税など計算問題に対応するため)
*/
export async function fetchProblems(topic?: string, limit = 20): Promise<Problem[]> {
if (!supabase) throw new Error('Supabase が設定されていません')
let query = supabase
.from('jq_problems')
.select('id, section, topic, difficulty, event_text, documents, symbols, debit, credit, choices, hint, explanation')
.eq('section', 'journal')
.limit(limit)
if (topic && topic !== 'all') {
query = query.eq('topic', topic)
}
const { data, error } = await query
if (error) throw new Error(`問題の取得に失敗しました: ${error.message}`)
return (data ?? []) as Problem[]
}
/** バンクが足りないときに Edge Function で補充生成する */
export async function generateProblems(topic: string, count = 5): Promise<Problem[]> {
if (!supabase) throw new Error('Supabase が設定されていません')
const { data, error } = await supabase.functions.invoke('jq-generate-problems', {
body: { topic, count },
})
if (error) throw new Error(`問題の生成に失敗しました: ${error.message}`)
return ((data?.problems ?? []) as Problem[])
}
/** 第2問(勘定記入)問題を取得する */
export async function fetchLedgerProblems(): Promise<LedgerProblem[]> {
if (!supabase) throw new Error('Supabase が設定されていません')
const { data, error } = await supabase
.from('jq_problems')
.select('id, section, topic, event_text, documents, problem_data, hint, explanation')
.eq('section', 'ledger')
if (error) throw new Error(`勘定記入問題の取得に失敗しました: ${error.message}`)
return (data ?? []).map((row) => {
const d = row.problem_data ?? {}
return {
id: row.id,
section: 'ledger' as const,
topic: row.topic,
account_name: d.account_name ?? '',
event_text: row.event_text,
documents: row.documents ?? undefined,
word_bank: d.word_bank ?? [],
rows: d.rows ?? [],
hint: row.hint,
explanation: row.explanation,
} satisfies LedgerProblem
})
}
/** 第3問(財務諸表)問題を取得する */
export async function fetchStatementProblems(): Promise<StatementProblem[]> {
if (!supabase) throw new Error('Supabase が設定されていません')
const { data, error } = await supabase
.from('jq_problems')
.select('id, section, topic, event_text, documents, problem_data, hint, explanation')
.eq('section', 'statement')
if (error) throw new Error(`財務諸表問題の取得に失敗しました: ${error.message}`)
return (data ?? []).map((row) => {
const d = row.problem_data ?? {}
return {
id: row.id,
section: 'statement' as const,
topic: row.topic,
event_text: row.event_text,
documents: row.documents ?? undefined,
bs_rows: d.bs_rows ?? [],
hint: row.hint,
explanation: row.explanation,
} satisfies StatementProblem
})
}
/** プレイ結果の記録(認証済みユーザーのみ呼ぶ) */
export async function recordAttempt(problemId: string, isCorrect: boolean): Promise<void> {
if (!supabase) return
const { error } = await supabase
.from('jq_attempts')
.insert({ problem_id: problemId, is_correct: isCorrect })
if (error) console.warn('recordAttempt failed', error)
}