refactor files

This commit is contained in:
2026-04-12 23:36:14 +07:00
parent 20ae176992
commit 406d7039d6
45 changed files with 162 additions and 255 deletions

View File

@@ -1,157 +0,0 @@
import type { Question, VocabWord, WritingFeedback, ToeicPart } from '@/types'
export const TOEIC_PARTS: ToeicPart[] = [
{ id: 1, name: 'Part 1', nameVi: 'Mô tả hình ảnh', questionCount: 45, icon: 'image', progressPercent: 60 },
{ id: 2, name: 'Part 2', nameVi: 'Hỏi-đáp', questionCount: 30, icon: 'question_answer', progressPercent: 40 },
{ id: 3, name: 'Part 3', nameVi: 'Đoạn hội thoại', questionCount: 39, icon: 'forum', progressPercent: 25 },
{ id: 4, name: 'Part 4', nameVi: 'Bài nói', questionCount: 30, icon: 'record_voice_over', progressPercent: 10 },
{ id: 5, name: 'Part 5', nameVi: 'Điền từ', questionCount: 40, icon: 'history_edu', progressPercent: 80 },
{ id: 6, name: 'Part 6', nameVi: 'Điền đoạn', questionCount: 16, icon: 'article', progressPercent: 50 },
{ id: 7, name: 'Part 7', nameVi: 'Đọc hiểu', questionCount: 54, icon: 'chrome_reader_mode', progressPercent: 30 },
]
export const MOCK_QUESTIONS: Question[] = [
{
id: 'q1', part: 2,
text: 'What does the man suggest the woman do about the budget report?',
options: ['A. Submit it immediately', 'B. Review it again carefully', 'C. Postpone the deadline', 'D. Ask a colleague for help'],
correctAnswer: 1,
explanation: 'Người đàn ông nói "You should review it carefully before submitting" — gợi ý xem xét lại báo cáo trước khi nộp.',
},
{
id: 'q2', part: 2,
text: 'Where most likely are the speakers?',
options: ['A. In a restaurant', 'B. At a conference', 'C. In an office', 'D. At an airport'],
correctAnswer: 2,
explanation: 'Các từ như "meeting room", "printer", "desk" cho biết cuộc trò chuyện diễn ra trong văn phòng.',
},
{
id: 'q3', part: 2,
text: 'Why is the man calling?',
options: ['A. To confirm a reservation', 'B. To cancel an appointment', 'C. To reschedule a meeting', 'D. To order supplies'],
correctAnswer: 0,
explanation: 'Từ "confirm" và "booking number" trong hội thoại chỉ rõ mục đích của cuộc gọi là xác nhận đặt chỗ.',
},
{
id: 'q4', part: 2,
text: 'What will the woman do next?',
options: ['A. Call the manager', 'B. Send an email', 'C. Check the inventory', 'D. Update the schedule'],
correctAnswer: 3,
explanation: 'Người phụ nữ nói "I\'ll update the schedule right away" — cho biết hành động tiếp theo là cập nhật lịch trình.',
},
{
id: 'q5', part: 2,
text: 'What problem does the man mention?',
options: ['A. A delayed shipment', 'B. A broken device', 'C. A missing document', 'D. A scheduling conflict'],
correctAnswer: 0,
explanation: '"The delivery has been delayed by two days" — vấn đề được đề cập là lô hàng bị trễ.',
},
{
id: 'q6', part: 2,
text: 'How does the woman respond to the proposal?',
options: ['A. She accepts it', 'B. She rejects it', 'C. She needs more time', 'D. She suggests modifications'],
correctAnswer: 3,
explanation: '"That sounds good, but maybe we could adjust the timeline a bit" — đề xuất điều chỉnh, không chấp nhận hoàn toàn.',
},
{
id: 'q7', part: 2,
text: 'What is the purpose of the announcement?',
options: ['A. To introduce new products', 'B. To notify schedule changes', 'C. To welcome new employees', 'D. To announce a promotion'],
correctAnswer: 1,
explanation: 'Thông báo nói về việc thay đổi giờ làm việc từ tuần tới — mục đích là thông báo thay đổi lịch.',
},
{
id: 'q8', part: 2,
text: 'What does the woman ask the man to do?',
options: ['A. Prepare a presentation', 'B. Contact the client', 'C. Review the contract', 'D. Attend a training session'],
correctAnswer: 2,
explanation: '"Could you go over the contract before we sign?" — người phụ nữ yêu cầu xem lại hợp đồng.',
},
{
id: 'q9', part: 2,
text: 'When will the project be completed?',
options: ['A. By the end of this week', 'B. Next Monday', 'C. In two weeks', 'D. Next month'],
correctAnswer: 0,
explanation: '"We should be finished by Friday" — dự án sẽ hoàn thành vào cuối tuần này.',
},
{
id: 'q10', part: 2,
text: 'What is being discussed at the meeting?',
options: ['A. Budget allocations', 'B. Marketing strategies', 'C. Product launches', 'D. Staff promotions'],
correctAnswer: 1,
explanation: 'Cuộc họp tập trung vào "the new advertising campaign and social media approach" — chiến lược marketing.',
},
]
export const VOCAB_DATA: Record<string, VocabWord[]> = {
'Tất cả': [
{ id: 'v1', word: 'negotiate', phonetic: '/nɪˈɡoʊʃieɪt/', meaningVi: 'đàm phán', topic: 'Business', example: 'We need to negotiate the contract terms before signing.' },
{ id: 'v2', word: 'collaborate', phonetic: '/kəˈlæbəreɪt/', meaningVi: 'hợp tác', topic: 'Business', example: 'Teams need to collaborate effectively to meet the deadline.' },
{ id: 'v3', word: 'agenda', phonetic: '/əˈdʒendə/', meaningVi: 'chương trình nghị sự', topic: 'Office', example: 'The agenda has been sent to all meeting participants.' },
{ id: 'v4', word: 'itinerary', phonetic: '/aɪˈtɪnəreri/', meaningVi: 'lịch trình chuyến đi', topic: 'Travel', example: 'Here is your travel itinerary for the business conference.' },
{ id: 'v5', word: 'reimburse', phonetic: '/ˌriːɪmˈːrs/', meaningVi: 'hoàn tiền', topic: 'Finance', example: 'The company will reimburse your travel expenses.' },
{ id: 'v6', word: 'recruit', phonetic: '/rɪˈkruːt/', meaningVi: 'tuyển dụng', topic: 'HR', example: 'We are actively recruiting experienced engineers.' },
{ id: 'v7', word: 'campaign', phonetic: '/kæmˈpeɪn/', meaningVi: 'chiến dịch', topic: 'Marketing', example: 'The marketing campaign was very successful this quarter.' },
{ id: 'v8', word: 'implement', phonetic: '/ˈɪmplɪment/', meaningVi: 'triển khai, thực hiện', topic: 'Business', example: 'We plan to implement the new strategy next quarter.' },
],
'Business': [
{ id: 'b1', word: 'negotiate', phonetic: '/nɪˈɡoʊʃieɪt/', meaningVi: 'đàm phán', topic: 'Business', example: 'We need to negotiate the contract terms.' },
{ id: 'b2', word: 'collaborate', phonetic: '/kəˈlæbəreɪt/', meaningVi: 'hợp tác', topic: 'Business', example: 'Teams collaborate to achieve shared goals.' },
{ id: 'b3', word: 'delegate', phonetic: '/ˈdelɪɡeɪt/', meaningVi: 'uỷ quyền, phân công', topic: 'Business', example: 'A good manager knows how to delegate tasks.' },
{ id: 'b4', word: 'implement', phonetic: '/ˈɪmplɪment/', meaningVi: 'triển khai, thực hiện', topic: 'Business', example: 'We will implement the new policy next month.' },
{ id: 'b5', word: 'merger', phonetic: '/ˈːrdʒər/', meaningVi: 'sáp nhập công ty', topic: 'Business', example: 'The merger will create a stronger combined company.' },
{ id: 'b6', word: 'acquisition', phonetic: '/ˌækwɪˈzɪʃən/', meaningVi: 'mua lại, thâu tóm', topic: 'Business', example: 'The acquisition was completed ahead of schedule.' },
],
'Office': [
{ id: 'o1', word: 'agenda', phonetic: '/əˈdʒendə/', meaningVi: 'chương trình nghị sự', topic: 'Office', example: 'Please review the agenda before the meeting.' },
{ id: 'o2', word: 'minutes', phonetic: '/ˈmɪnɪts/', meaningVi: 'biên bản họp', topic: 'Office', example: 'Could you take the meeting minutes today?' },
{ id: 'o3', word: 'submit', phonetic: '/səbˈmɪt/', meaningVi: 'nộp, gửi đi', topic: 'Office', example: 'Please submit your report by Friday afternoon.' },
{ id: 'o4', word: 'deadline', phonetic: '/ˈdedlaɪn/', meaningVi: 'hạn chót', topic: 'Office', example: 'The deadline for this project is end of month.' },
{ id: 'o5', word: 'cubicle', phonetic: '/ˈkjuːbɪkəl/', meaningVi: 'góc làm việc riêng', topic: 'Office', example: 'Each employee has their own cubicle in the open office.' },
],
'Travel': [
{ id: 't1', word: 'itinerary', phonetic: '/aɪˈtɪnəreri/', meaningVi: 'lịch trình chuyến đi', topic: 'Travel', example: 'Here is your detailed travel itinerary.' },
{ id: 't2', word: 'boarding pass', phonetic: '/ˈːrdɪŋ pæs/', meaningVi: 'thẻ lên máy bay', topic: 'Travel', example: 'Please have your boarding pass ready at the gate.' },
{ id: 't3', word: 'layover', phonetic: '/ˈleɪoʊvər/', meaningVi: 'thời gian quá cảnh', topic: 'Travel', example: 'There is a two-hour layover in Singapore.' },
{ id: 't4', word: 'customs', phonetic: '/ˈkʌstəmz/', meaningVi: 'hải quan', topic: 'Travel', example: 'All passengers must go through customs on arrival.' },
{ id: 't5', word: 'baggage claim', phonetic: '/ˈɡɪdʒ kleɪm/', meaningVi: 'băng chuyền hành lý', topic: 'Travel', example: 'Meet us at the baggage claim after landing.' },
],
'Finance': [
{ id: 'f1', word: 'reimburse', phonetic: '/ˌriːɪmˈːrs/', meaningVi: 'hoàn tiền', topic: 'Finance', example: 'The company will reimburse all travel expenses.' },
{ id: 'f2', word: 'invoice', phonetic: '/ˈɪnvɔɪs/', meaningVi: 'hoá đơn', topic: 'Finance', example: 'Please send the invoice to our accounting department.' },
{ id: 'f3', word: 'budget', phonetic: '/ˈbʌdʒɪt/', meaningVi: 'ngân sách', topic: 'Finance', example: 'We need to stay within the approved budget.' },
{ id: 'f4', word: 'revenue', phonetic: '/ˈrevɪnjuː/', meaningVi: 'doanh thu', topic: 'Finance', example: 'Revenue increased by 15% last quarter.' },
{ id: 'f5', word: 'fiscal year', phonetic: '/ˈfɪskəl jɪər/', meaningVi: 'năm tài chính', topic: 'Finance', example: 'Our fiscal year ends on December 31st.' },
],
'HR': [
{ id: 'h1', word: 'recruit', phonetic: '/rɪˈkruːt/', meaningVi: 'tuyển dụng', topic: 'HR', example: 'We are recruiting experienced software engineers.' },
{ id: 'h2', word: 'probation', phonetic: '/proʊˈbeɪʃən/', meaningVi: 'thử việc', topic: 'HR', example: 'New employees have a 3-month probation period.' },
{ id: 'h3', word: 'appraisal', phonetic: '/əˈpreɪzəl/', meaningVi: 'đánh giá nhân viên', topic: 'HR', example: 'Annual performance appraisals are held in December.' },
{ id: 'h4', word: 'resignation', phonetic: '/ˌrezɪɡˈneɪʃən/', meaningVi: 'đơn từ chức', topic: 'HR', example: 'She submitted her resignation letter this morning.' },
{ id: 'h5', word: 'onboarding', phonetic: '/ˈɒnbɔːrdɪŋ/', meaningVi: 'quy trình tiếp nhận nhân viên mới', topic: 'HR', example: 'The onboarding process takes about two weeks.' },
],
'Marketing': [
{ id: 'm1', word: 'campaign', phonetic: '/kæmˈpeɪn/', meaningVi: 'chiến dịch', topic: 'Marketing', example: 'The marketing campaign exceeded all expectations.' },
{ id: 'm2', word: 'demographics', phonetic: '/ˌdeməˈɡræfɪks/', meaningVi: 'nhân khẩu học', topic: 'Marketing', example: 'We need to understand our target demographics.' },
{ id: 'm3', word: 'endorse', phonetic: '/ɪnˈːrs/', meaningVi: 'chứng thực, bảo trợ', topic: 'Marketing', example: 'The product is endorsed by professional athletes.' },
{ id: 'm4', word: 'branding', phonetic: '/ˈbrændɪŋ/', meaningVi: 'xây dựng thương hiệu', topic: 'Marketing', example: 'Consistent branding builds long-term customer trust.' },
{ id: 'm5', word: 'conversion rate', phonetic: '/kənˈːrʒən reɪt/', meaningVi: 'tỷ lệ chuyển đổi', topic: 'Marketing', example: 'Our conversion rate improved after the redesign.' },
],
}
export const MOCK_WRITING_FEEDBACK: WritingFeedback = {
score: '6.5',
grammar: [
'"managers are concern" → nên dùng "concerned" (tính từ, không phải danh từ)',
'Thiếu mạo từ "an" trước "efficient arrangement" ở câu cuối',
'Câu "This change is expected to improve" — đúng nhưng hơi thụ động, có thể dùng active voice',
],
vocabulary: [
'Tốt: "implement", "productivity", "collaboration", "arrangement"',
'Gợi ý nâng cao: "enhance" thay "increase", "address" thay "help with"',
'Nên thêm từ nối: "Nevertheless", "In addition", "As a result of this"',
],
structure: 'Bài viết có cấu trúc khá rõ ràng với mở đầu, thân bài và kết luận ngầm. Tuy nhiên cần phát triển thêm phần giải thích tác động và thêm ví dụ cụ thể để bài hoàn chỉnh hơn.',
improvedVersion: 'The company has decided to implement a new remote work policy starting next month. All employees will be able to work from home for three days per week. This change is expected to enhance work-life balance and boost overall productivity. Nevertheless, some managers are concerned about communication challenges and team collaboration. To address these concerns, the HR department will organize training sessions to help teams adapt to this new arrangement effectively.',
summary: 'Bài viết đạt mức Upper Intermediate (6.5) với ý tưởng rõ ràng. Cần sửa lỗi ngữ pháp cơ bản và bổ sung từ vựng phong phú hơn để đạt band 7.0+.',
}

View File

@@ -1,7 +1,7 @@
import { useEffect } from 'react'
import { useNavigate } from '@tanstack/react-router'
import { useUser } from '@/hooks/use-auth'
import { LoginForm } from '@/components/auth/LoginForm'
import { LoginForm } from './LoginForm'
export function LoginPage() {
const user = useUser()

View File

@@ -1,7 +1,7 @@
import { useEffect } from 'react'
import { useNavigate } from '@tanstack/react-router'
import { useUser } from '@/hooks/use-auth'
import { RegisterForm } from '@/components/auth/RegisterForm'
import { RegisterForm } from './RegisterForm'
export function RegisterPage() {
const user = useUser()

View File

@@ -3,11 +3,11 @@ import { useAuthStore } from '@/store/auth-store'
import { useAuthModalStore } from '@/store/auth-modal-store'
import { useGamification, useLeaderboard } from '@/hooks/use-gamification'
import { XP_REWARDS } from '@/lib/gamification-service'
import { StatsRow } from './dashboard/StatsRow'
import { XpProgressCard } from './dashboard/XpProgressCard'
import { WeeklySection } from './dashboard/WeeklySection'
import { XuEconomyCard } from './dashboard/XuEconomyCard'
import { LeaderboardCard } from './dashboard/LeaderboardCard'
import { StatsRow } from './StatsRow'
import { XpProgressCard } from './XpProgressCard'
import { WeeklySection } from './WeeklySection'
import { XuEconomyCard } from './XuEconomyCard'
import { LeaderboardCard } from './LeaderboardCard'
// Numeric level from XP (1 per 100 XP, min 1)
export function calcNumericLevel(xp: number) {

View File

@@ -1,5 +1,5 @@
import type { UserLevel } from '@/types'
import { calcNumericLevel } from '../Dashboard'
import { calcNumericLevel } from './Dashboard'
const LEVEL_NAMES: Record<UserLevel, string> = {
beginner: 'Beginner',

View File

@@ -1,4 +1,4 @@
import { calcXpNextLevel, calcNumericLevel } from '../Dashboard'
import { calcXpNextLevel, calcNumericLevel } from './Dashboard'
interface Props { xp: number }

View File

@@ -1,11 +1,11 @@
import { useAuthStore } from '@/store/auth-store'
import { useAuthModalStore } from '@/store/auth-modal-store'
import { ProfileCard } from './settings/ProfileCard'
import { XuWalletCard } from './settings/XuWalletCard'
import { DailyGoalCard } from './settings/DailyGoalCard'
import { ExamDateCard } from './settings/ExamDateCard'
import { NotificationsCard } from './settings/NotificationsCard'
import { AccountCard } from './settings/AccountCard'
import { ProfileCard } from './ProfileCard'
import { XuWalletCard } from './XuWalletCard'
import { DailyGoalCard } from './DailyGoalCard'
import { ExamDateCard } from './ExamDateCard'
import { NotificationsCard } from './NotificationsCard'
import { AccountCard } from './AccountCard'
export function Settings() {
const user = useAuthStore((s) => s.user)

View File

@@ -2,7 +2,7 @@ import { useState } from 'react'
import { useNavigate } from '@tanstack/react-router'
import { CircularProgress } from '@/components/CircularProgress'
import { useTestStore } from '@/store/test-store'
import { TOEIC_PARTS } from '@/data/mock-data'
import { TOEIC_PARTS } from '@/temp/local-data'
import { fetchQuestions } from '@/hooks/use-questions'
import { useRequireAuth } from '@/hooks/use-require-auth'

View File

@@ -1,6 +1,6 @@
import { useState } from 'react'
import { cn } from '@/lib/utils'
import { FlashCard } from '@/components/FlashCard'
import { FlashCard } from './FlashCard'
import { useVocabStore } from '@/store/vocab-store'
import { useVocab } from '@/hooks/use-vocab'
import { VOCAB_TOPICS } from '@/types'
@@ -170,7 +170,6 @@ export function Vocabulary() {
Trước
</button>
{/* Mark buttons */}
<div className="flex gap-2">
<button
onClick={handleMarkReview}
@@ -203,7 +202,6 @@ export function Vocabulary() {
{/* Right: Stats — desktop only */}
<div className="hidden lg:flex flex-col gap-4 w-52 flex-shrink-0">
{/* Today stats */}
<div className="bg-white rounded-2xl border border-slate-200 p-4">
<div className="text-xs text-slate-400 font-semibold uppercase tracking-wider mb-3">Thống </div>
<div className="space-y-3">
@@ -229,7 +227,6 @@ export function Vocabulary() {
</div>
</div>
{/* Recently known */}
{recentKnown.length > 0 && (
<div className="bg-white rounded-2xl border border-slate-200 p-4">
<div className="text-xs text-slate-400 font-semibold uppercase tracking-wider mb-3">Vừa thuộc</div>

View File

@@ -1,64 +0,0 @@
// Phase 3 bridge: gamification state from localStorage until DB is live
export interface GamificationState {
xu: number
streak: number
xp: number
xpNextLevel: number
level: number
levelName: string
weeklyCompleted: number
weeklyGoal: number
weekActivity: boolean[] // MonSun, true = completed
}
const KEYS = {
xu: 'xu_balance',
streak: 'gamification_streak',
xp: 'gamification_xp',
level: 'gamification_level',
weeklyCompleted: 'gamification_weekly_completed',
}
function getNum(key: string, fallback: number) {
const v = localStorage.getItem(key)
return v ? parseInt(v, 10) : fallback
}
function getLevelName(level: number): string {
if (level >= 40) return 'Master'
if (level >= 20) return 'Gold'
if (level >= 10) return 'Silver'
if (level >= 5) return 'Bronze'
return 'Beginner'
}
function getWeekActivity(): boolean[] {
// Days MonSun — mark days up to (but not including) today as done if streak is active
const today = new Date().getDay() // 0=Sun, 1=Mon ... 6=Sat
const streak = getNum(KEYS.streak, 14)
// Convert to Mon=0 index
const todayIdx = today === 0 ? 6 : today - 1
const activity = Array(7).fill(false)
for (let i = 0; i < Math.min(todayIdx, streak, 7); i++) {
activity[i] = true
}
return activity
}
export function loadGamification(): GamificationState {
const level = getNum(KEYS.level, 14)
const xp = getNum(KEYS.xp, 1200)
return {
xu: getNum(KEYS.xu, 50),
streak: getNum(KEYS.streak, 14),
xp,
xpNextLevel: 1600, // hardcoded for Phase 3 demo
level,
levelName: getLevelName(level),
weeklyCompleted: getNum(KEYS.weeklyCompleted, 3),
weeklyGoal: 5,
weekActivity: getWeekActivity(),
}
}

View File

@@ -1,9 +1,9 @@
import { createRootRoute, Outlet } from '@tanstack/react-router'
import { useEffect } from 'react'
import { Sidebar } from '@/components/Sidebar'
import { AppHeader } from '@/components/AppHeader'
import { MobileNav } from '@/components/MobileNav'
import { AuthModal } from '@/components/auth/AuthModal'
import { Sidebar } from '@/components/layout/Sidebar'
import { AppHeader } from '@/components/layout/AppHeader'
import { MobileNav } from '@/components/layout/MobileNav'
import { AuthModal } from '@/features/auth/components/AuthModal'
import { useAuthStore } from '@/store/auth-store'
export const Route = createRootRoute({

View File

@@ -1,5 +1,5 @@
import { createFileRoute } from '@tanstack/react-router'
import { LoginPage } from '@/pages/Login'
import { LoginPage } from '@/features/auth/components/LoginPage'
export const Route = createFileRoute('/auth/login')({
component: LoginPage,

View File

@@ -1,5 +1,5 @@
import { createFileRoute } from '@tanstack/react-router'
import { RegisterPage } from '@/pages/Register'
import { RegisterPage } from '@/features/auth/components/RegisterPage'
export const Route = createFileRoute('/auth/register')({
component: RegisterPage,

View File

@@ -1,5 +1,5 @@
import { createFileRoute } from '@tanstack/react-router'
import { Dashboard } from '@/pages/Dashboard'
import { Dashboard } from '@/features/dashboard/components/Dashboard'
export const Route = createFileRoute('/dashboard')({
component: Dashboard,

View File

@@ -1,5 +1,5 @@
import { createFileRoute } from "@tanstack/react-router"
import { Home } from "@/pages/Home"
import { Home } from "@/features/home/components/Home"
export const Route = createFileRoute("/")({
component: Home,

View File

@@ -1,5 +1,5 @@
import { createFileRoute } from '@tanstack/react-router'
import { Settings } from '@/pages/Settings'
import { Settings } from '@/features/settings/components/Settings'
export const Route = createFileRoute('/settings')({
component: Settings,

View File

@@ -1,5 +1,5 @@
import { createFileRoute } from "@tanstack/react-router"
import { ToeicPractice } from "@/pages/ToeicPractice"
import { ToeicPractice } from "@/features/toeic/components/ToeicPractice"
export const Route = createFileRoute("/toeic/")({
component: ToeicPractice,

View File

@@ -1,5 +1,5 @@
import { createFileRoute } from "@tanstack/react-router"
import { TestResult } from "@/pages/TestResult"
import { TestResult } from "@/features/toeic/components/TestResult"
export const Route = createFileRoute("/toeic/result")({
component: TestResult,

View File

@@ -1,5 +1,5 @@
import { createFileRoute } from "@tanstack/react-router"
import { TestSession } from "@/pages/TestSession"
import { TestSession } from "@/features/toeic/components/TestSession"
export const Route = createFileRoute("/toeic/session")({
component: TestSession,

View File

@@ -1,5 +1,5 @@
import { createFileRoute } from "@tanstack/react-router"
import { Vocabulary } from "@/pages/Vocabulary"
import { Vocabulary } from "@/features/vocab/components/Vocabulary"
export const Route = createFileRoute("/vocab")({
component: Vocabulary,

View File

@@ -1,5 +1,5 @@
import { createFileRoute } from "@tanstack/react-router"
import { WritingChecker } from "@/pages/WritingChecker"
import { WritingChecker } from "@/features/writing/components/WritingChecker"
export const Route = createFileRoute("/writing")({
component: WritingChecker,

131
src/temp/local-data.ts Normal file
View File

@@ -0,0 +1,131 @@
/**
* TEMPORARY LOCAL DATA
* ====================
* This file contains all placeholder, mock, and locally-hardcoded data.
* Each export is tagged with its status:
*
* [ACTIVE TEMP] — still used in production code; needs real DB data to replace it
* [UNUSED] — not imported anywhere; kept as reference until Supabase seed is confirmed
* [SUPERSEDED] — replaced by real DB service, kept for reference only
*
* When real database data is available, remove the relevant export and update the consumer.
*/
import type { Question, VocabWord, WritingFeedback, ToeicPart } from '@/types'
// ─── [ACTIVE TEMP] ─────────────────────────────────────────────────────────────
// Used by: src/pages/ToeicPractice.tsx
// Replace with: DB query on `questions` table (group by part, count) + user progress %
// Note: `progressPercent` is hardcoded — user's real per-part progress should come from user_progress
export const TOEIC_PARTS: ToeicPart[] = [
{ id: 1, name: 'Part 1', nameVi: 'Mô tả hình ảnh', questionCount: 45, icon: 'image', progressPercent: 60 },
{ id: 2, name: 'Part 2', nameVi: 'Hỏi-đáp', questionCount: 30, icon: 'question_answer', progressPercent: 40 },
{ id: 3, name: 'Part 3', nameVi: 'Đoạn hội thoại', questionCount: 39, icon: 'forum', progressPercent: 25 },
{ id: 4, name: 'Part 4', nameVi: 'Bài nói', questionCount: 30, icon: 'record_voice_over', progressPercent: 10 },
{ id: 5, name: 'Part 5', nameVi: 'Điền từ', questionCount: 40, icon: 'history_edu', progressPercent: 80 },
{ id: 6, name: 'Part 6', nameVi: 'Điền đoạn', questionCount: 16, icon: 'article', progressPercent: 50 },
{ id: 7, name: 'Part 7', nameVi: 'Đọc hiểu', questionCount: 54, icon: 'chrome_reader_mode', progressPercent: 30 },
]
// ─── [UNUSED] ──────────────────────────────────────────────────────────────────
// Real questions come from Supabase via fetchQuestions() in src/hooks/use-questions.ts
export const MOCK_QUESTIONS: Question[] = [
{ id: 'q1', part: 2, text: 'What does the man suggest the woman do about the budget report?', options: ['A. Submit it immediately', 'B. Review it again carefully', 'C. Postpone the deadline', 'D. Ask a colleague for help'], correctAnswer: 1, explanation: 'Người đàn ông nói "You should review it carefully before submitting" — gợi ý xem xét lại báo cáo trước khi nộp.' },
{ id: 'q2', part: 2, text: 'Where most likely are the speakers?', options: ['A. In a restaurant', 'B. At a conference', 'C. In an office', 'D. At an airport'], correctAnswer: 2, explanation: 'Các từ như "meeting room", "printer", "desk" cho biết cuộc trò chuyện diễn ra trong văn phòng.' },
{ id: 'q3', part: 2, text: 'Why is the man calling?', options: ['A. To confirm a reservation', 'B. To cancel an appointment', 'C. To reschedule a meeting', 'D. To order supplies'], correctAnswer: 0, explanation: 'Từ "confirm" và "booking number" trong hội thoại chỉ rõ mục đích của cuộc gọi là xác nhận đặt chỗ.' },
{ id: 'q4', part: 2, text: 'What will the woman do next?', options: ['A. Call the manager', 'B. Send an email', 'C. Check the inventory', 'D. Update the schedule'], correctAnswer: 3, explanation: 'Người phụ nữ nói "I\'ll update the schedule right away" — cho biết hành động tiếp theo là cập nhật lịch trình.' },
{ id: 'q5', part: 2, text: 'What problem does the man mention?', options: ['A. A delayed shipment', 'B. A broken device', 'C. A missing document', 'D. A scheduling conflict'], correctAnswer: 0, explanation: '"The delivery has been delayed by two days" — vấn đề được đề cập là lô hàng bị trễ.' },
{ id: 'q6', part: 2, text: 'How does the woman respond to the proposal?', options: ['A. She accepts it', 'B. She rejects it', 'C. She needs more time', 'D. She suggests modifications'], correctAnswer: 3, explanation: '"That sounds good, but maybe we could adjust the timeline a bit" — đề xuất điều chỉnh, không chấp nhận hoàn toàn.' },
{ id: 'q7', part: 2, text: 'What is the purpose of the announcement?', options: ['A. To introduce new products', 'B. To notify schedule changes', 'C. To welcome new employees', 'D. To announce a promotion'], correctAnswer: 1, explanation: 'Thông báo nói về việc thay đổi giờ làm việc từ tuần tới — mục đích là thông báo thay đổi lịch.' },
{ id: 'q8', part: 2, text: 'What does the woman ask the man to do?', options: ['A. Prepare a presentation', 'B. Contact the client', 'C. Review the contract', 'D. Attend a training session'], correctAnswer: 2, explanation: '"Could you go over the contract before we sign?" — người phụ nữ yêu cầu xem lại hợp đồng.' },
{ id: 'q9', part: 2, text: 'When will the project be completed?', options: ['A. By the end of this week', 'B. Next Monday', 'C. In two weeks', 'D. Next month'], correctAnswer: 0, explanation: '"We should be finished by Friday" — dự án sẽ hoàn thành vào cuối tuần này.' },
{ id: 'q10', part: 2, text: 'What is being discussed at the meeting?', options: ['A. Budget allocations', 'B. Marketing strategies', 'C. Product launches', 'D. Staff promotions'], correctAnswer: 1, explanation: 'Cuộc họp tập trung vào "the new advertising campaign and social media approach" — chiến lược marketing.' },
]
// ─── [UNUSED] ──────────────────────────────────────────────────────────────────
// Real vocab comes from Supabase via useVocab() in src/hooks/use-vocab.ts
export const VOCAB_DATA: Record<string, VocabWord[]> = {
'Tất cả': [
{ id: 'v1', word: 'negotiate', phonetic: '/nɪˈɡoʊʃieɪt/', meaningVi: 'đàm phán', topic: 'Business', example: 'We need to negotiate the contract terms before signing.' },
{ id: 'v2', word: 'collaborate', phonetic: '/kəˈlæbəreɪt/', meaningVi: 'hợp tác', topic: 'Business', example: 'Teams need to collaborate effectively to meet the deadline.' },
{ id: 'v3', word: 'agenda', phonetic: '/əˈdʒendə/', meaningVi: 'chương trình nghị sự', topic: 'Office', example: 'The agenda has been sent to all meeting participants.' },
{ id: 'v4', word: 'itinerary', phonetic: '/aɪˈtɪnəreri/', meaningVi: 'lịch trình chuyến đi', topic: 'Travel', example: 'Here is your travel itinerary for the business conference.' },
{ id: 'v5', word: 'reimburse', phonetic: '/ˌriːɪmˈːrs/', meaningVi: 'hoàn tiền', topic: 'Finance', example: 'The company will reimburse your travel expenses.' },
{ id: 'v6', word: 'recruit', phonetic: '/rɪˈkruːt/', meaningVi: 'tuyển dụng', topic: 'HR', example: 'We are actively recruiting experienced engineers.' },
{ id: 'v7', word: 'campaign', phonetic: '/kæmˈpeɪn/', meaningVi: 'chiến dịch', topic: 'Marketing', example: 'The marketing campaign was very successful this quarter.' },
{ id: 'v8', word: 'implement', phonetic: '/ˈɪmplɪment/', meaningVi: 'triển khai, thực hiện', topic: 'Business', example: 'We plan to implement the new strategy next quarter.' },
],
'Business': [
{ id: 'b1', word: 'negotiate', phonetic: '/nɪˈɡoʊʃieɪt/', meaningVi: 'đàm phán', topic: 'Business', example: 'We need to negotiate the contract terms.' },
{ id: 'b2', word: 'collaborate', phonetic: '/kəˈlæbəreɪt/', meaningVi: 'hợp tác', topic: 'Business', example: 'Teams collaborate to achieve shared goals.' },
{ id: 'b3', word: 'delegate', phonetic: '/ˈdelɪɡeɪt/', meaningVi: 'uỷ quyền, phân công', topic: 'Business', example: 'A good manager knows how to delegate tasks.' },
{ id: 'b4', word: 'implement', phonetic: '/ˈɪmplɪment/', meaningVi: 'triển khai, thực hiện', topic: 'Business', example: 'We will implement the new policy next month.' },
{ id: 'b5', word: 'merger', phonetic: '/ˈːrdʒər/', meaningVi: 'sáp nhập công ty', topic: 'Business', example: 'The merger will create a stronger combined company.' },
{ id: 'b6', word: 'acquisition', phonetic: '/ˌækwɪˈzɪʃən/', meaningVi: 'mua lại, thâu tóm', topic: 'Business', example: 'The acquisition was completed ahead of schedule.' },
],
'Office': [
{ id: 'o1', word: 'agenda', phonetic: '/əˈdʒendə/', meaningVi: 'chương trình nghị sự', topic: 'Office', example: 'Please review the agenda before the meeting.' },
{ id: 'o2', word: 'minutes', phonetic: '/ˈmɪnɪts/', meaningVi: 'biên bản họp', topic: 'Office', example: 'Could you take the meeting minutes today?' },
{ id: 'o3', word: 'submit', phonetic: '/səbˈmɪt/', meaningVi: 'nộp, gửi đi', topic: 'Office', example: 'Please submit your report by Friday afternoon.' },
{ id: 'o4', word: 'deadline', phonetic: '/ˈdedlaɪn/', meaningVi: 'hạn chót', topic: 'Office', example: 'The deadline for this project is end of month.' },
{ id: 'o5', word: 'cubicle', phonetic: '/ˈkjuːbɪkəl/', meaningVi: 'góc làm việc riêng', topic: 'Office', example: 'Each employee has their own cubicle in the open office.' },
],
'Travel': [
{ id: 't1', word: 'itinerary', phonetic: '/aɪˈtɪnəreri/', meaningVi: 'lịch trình chuyến đi', topic: 'Travel', example: 'Here is your detailed travel itinerary.' },
{ id: 't2', word: 'boarding pass', phonetic: '/ˈːrdɪŋ pæs/', meaningVi: 'thẻ lên máy bay', topic: 'Travel', example: 'Please have your boarding pass ready at the gate.' },
{ id: 't3', word: 'layover', phonetic: '/ˈleɪoʊvər/', meaningVi: 'thời gian quá cảnh', topic: 'Travel', example: 'There is a two-hour layover in Singapore.' },
{ id: 't4', word: 'customs', phonetic: '/ˈkʌstəmz/', meaningVi: 'hải quan', topic: 'Travel', example: 'All passengers must go through customs on arrival.' },
{ id: 't5', word: 'baggage claim', phonetic: '/ˈɡɪdʒ kleɪm/', meaningVi: 'băng chuyền hành lý', topic: 'Travel', example: 'Meet us at the baggage claim after landing.' },
],
'Finance': [
{ id: 'f1', word: 'reimburse', phonetic: '/ˌriːɪmˈːrs/', meaningVi: 'hoàn tiền', topic: 'Finance', example: 'The company will reimburse all travel expenses.' },
{ id: 'f2', word: 'invoice', phonetic: '/ˈɪnvɔɪs/', meaningVi: 'hoá đơn', topic: 'Finance', example: 'Please send the invoice to our accounting department.' },
{ id: 'f3', word: 'budget', phonetic: '/ˈbʌdʒɪt/', meaningVi: 'ngân sách', topic: 'Finance', example: 'We need to stay within the approved budget.' },
{ id: 'f4', word: 'revenue', phonetic: '/ˈrevɪnjuː/', meaningVi: 'doanh thu', topic: 'Finance', example: 'Revenue increased by 15% last quarter.' },
{ id: 'f5', word: 'fiscal year', phonetic: '/ˈfɪskəl jɪər/', meaningVi: 'năm tài chính', topic: 'Finance', example: 'Our fiscal year ends on December 31st.' },
],
'HR': [
{ id: 'h1', word: 'recruit', phonetic: '/rɪˈkruːt/', meaningVi: 'tuyển dụng', topic: 'HR', example: 'We are recruiting experienced software engineers.' },
{ id: 'h2', word: 'probation', phonetic: '/proʊˈbeɪʃən/', meaningVi: 'thử việc', topic: 'HR', example: 'New employees have a 3-month probation period.' },
{ id: 'h3', word: 'appraisal', phonetic: '/əˈpreɪzəl/', meaningVi: 'đánh giá nhân viên', topic: 'HR', example: 'Annual performance appraisals are held in December.' },
{ id: 'h4', word: 'resignation', phonetic: '/ˌrezɪɡˈneɪʃən/', meaningVi: 'đơn từ chức', topic: 'HR', example: 'She submitted her resignation letter this morning.' },
{ id: 'h5', word: 'onboarding', phonetic: '/ˈɒnbɔːrdɪŋ/', meaningVi: 'quy trình tiếp nhận nhân viên mới', topic: 'HR', example: 'The onboarding process takes about two weeks.' },
],
'Marketing': [
{ id: 'm1', word: 'campaign', phonetic: '/kæmˈpeɪn/', meaningVi: 'chiến dịch', topic: 'Marketing', example: 'The marketing campaign exceeded all expectations.' },
{ id: 'm2', word: 'demographics', phonetic: '/ˌdeməˈɡræfɪks/', meaningVi: 'nhân khẩu học', topic: 'Marketing', example: 'We need to understand our target demographics.' },
{ id: 'm3', word: 'endorse', phonetic: '/ɪnˈːrs/', meaningVi: 'chứng thực, bảo trợ', topic: 'Marketing', example: 'The product is endorsed by professional athletes.' },
{ id: 'm4', word: 'branding', phonetic: '/ˈbrændɪŋ/', meaningVi: 'xây dựng thương hiệu', topic: 'Marketing', example: 'Consistent branding builds long-term customer trust.' },
{ id: 'm5', word: 'conversion rate', phonetic: '/kənˈːrʒən reɪt/', meaningVi: 'tỷ lệ chuyển đổi', topic: 'Marketing', example: 'Our conversion rate improved after the redesign.' },
],
}
// ─── [UNUSED] ──────────────────────────────────────────────────────────────────
// Real writing feedback is generated server-side via the GLM Edge Function
// Used only as a visual reference during development
export const MOCK_WRITING_FEEDBACK: WritingFeedback = {
score: '6.5',
grammar: [
'"managers are concern" → nên dùng "concerned" (tính từ, không phải danh từ)',
'Thiếu mạo từ "an" trước "efficient arrangement" ở câu cuối',
'Câu "This change is expected to improve" — đúng nhưng hơi thụ động, có thể dùng active voice',
],
vocabulary: [
'Tốt: "implement", "productivity", "collaboration", "arrangement"',
'Gợi ý nâng cao: "enhance" thay "increase", "address" thay "help with"',
'Nên thêm từ nối: "Nevertheless", "In addition", "As a result of this"',
],
structure: 'Bài viết có cấu trúc khá rõ ràng với mở đầu, thân bài và kết luận ngầm. Tuy nhiên cần phát triển thêm phần giải thích tác động và thêm ví dụ cụ thể để bài hoàn chỉnh hơn.',
improvedVersion: 'The company has decided to implement a new remote work policy starting next month. All employees will be able to work from home for three days per week. This change is expected to enhance work-life balance and boost overall productivity. Nevertheless, some managers are concerned about communication challenges and team collaboration. To address these concerns, the HR department will organize training sessions to help teams adapt to this new arrangement effectively.',
summary: 'Bài viết đạt mức Upper Intermediate (6.5) với ý tưởng rõ ràng. Cần sửa lỗi ngữ pháp cơ bản và bổ sung từ vựng phong phú hơn để đạt band 7.0+.',
}
// ─── [SUPERSEDED] ─────────────────────────────────────────────────────────────
// Was: src/pages/dashboard/gamification-store.ts
// Replaced by: src/lib/gamification-service.ts + src/hooks/use-gamification.ts (Supabase)
// Kept here for reference — DO NOT import in production code
export interface _LegacyGamificationState {
xu: number; streak: number; xp: number; xpNextLevel: number
level: number; levelName: string; weeklyCompleted: number
weeklyGoal: number; weekActivity: boolean[]
}