Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
87b0ee9
feat: integrate SearchBar and SSelect components in Workspace3dLibrar…
meewaldor Dec 8, 2025
6351c55
Merge branch 'dev' of https://github.com/Capstone-STEMify/STEMify-Fro…
meewaldor Dec 8, 2025
85b80c2
feat: enhance emulation card layout and update popover functionality …
meewaldor Dec 8, 2025
ffd2391
feat: add user management features and enhance filtering options in O…
LeThanhNhan91 Dec 8, 2025
bf5a031
Merge branch 'dev' of https://github.com/Capstone-STEMify/STEMify-Fro…
LeThanhNhan91 Dec 8, 2025
d9a96ea
feat: add GLB export functionality and update SceneActions for export…
meewaldor Dec 8, 2025
d4da486
Merge branch 'dev' of https://github.com/Capstone-STEMify/STEMify-Fro…
meewaldor Dec 8, 2025
f8924b2
feat: add status filtering and improve translations in classroom comp…
ttd11204 Dec 8, 2025
30366a4
Merge branch 'dev' of github-tieumylam:Capstone-STEMify/STEMify-Front…
ttd11204 Dec 8, 2025
12ee861
feat: enhance classroom and common translations, improve breadcrumb n…
ttd11204 Dec 8, 2025
b438cba
feat: update organization admin terminology, enhance Vietnamese trans…
LeThanhNhan91 Dec 8, 2025
5ce5436
feat: update lesson and quiz components with new translations and UI …
ttd11204 Dec 8, 2025
1e67cff
Merge branch 'dev' of github-tieumylam:Capstone-STEMify/STEMify-Front…
ttd11204 Dec 8, 2025
8d9a375
feat: add due date validation for quiz attempt selection
ttd11204 Dec 8, 2025
f910a2d
feat: remove class code description and comment out Google Meet Card
ttd11204 Dec 8, 2025
b3713f0
feat: enhance translations and UI components for better user experience
ttd11204 Dec 8, 2025
6c7dfec
feat: add upgrade button translation and update AuthStatusMenu to use it
ttd11204 Dec 8, 2025
3630e36
feat: simplify student avatar rendering and remove redundant properties
ttd11204 Dec 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion messages/en/classroom/en_classroom.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
"classroom": {
"list": {
"header": "Classroom List",
"description": "Manage all your existing classrooms, including class details, schedules, teachers, and enrolled students.",
"searchPlaceholder": "Search...",
"selectCoursePlaceholder": "Select course",
"courses": "courses"
"selectStatusPlaceholder": "Filter by status",
"courses": "courses",
"noClassroom": "No classrooms found.",
"noClassroomSubtext": "Try adjusting your search or filter to find what you're looking for."
},
"update": {
"basicInfo": {
Expand Down
33 changes: 31 additions & 2 deletions messages/en/common/en_common.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
{
"common": {
"noData": "Not found",
"breadcrumb": {
"home": "Home",
"resource": "Resources",
"lesson": "Lesson",
"lessons": "Lessons",
"activities": "Activities",
"course": "Course",
"courses": "Courses",
"courseDetail": "Course Detail",
"classroom": "Classroom",
"classrooms": "Classrooms",
"classroomDetail": "Classroom Detail",
"createClassroom": "Create Classroom"
},
"search": {
"placeholder": "Search...",
"noResults": "No results found."
Expand Down Expand Up @@ -115,7 +130,12 @@
"continueLearning": "Continue Learning",
"markAsComplete": "Mark as Complete",
"startQuiz": "Start Quiz",
"contact": "Contact Us"
"contact": "Contact Us",
"menu": "Open Menu",
"exportRSA": "Export RSA",
"exporting": "Exporting...",
"downloadAndPrint": "Download & Print",
"upgrade": "Upgrade Plan"
},
"message": {
"courseCreateSuccess": "Course created successfully!",
Expand Down Expand Up @@ -198,7 +218,16 @@
"course": "Course",
"joinedAt": "Joined At",
"subscription": "Subscription",
"student": "Student(s)"
"student": "Student(s)",
"user": "User",
"license": "License",
"groupName": "Group",
"className": "Class Name",
"menu": "Open Menu",
"score": "Score",
"correctAnswer": "Correct Answer",
"submissionDate": "Submission Date",
"studentGroup": "Student Group"
},
"paging": {
"previous": "Previous",
Expand Down
1 change: 1 addition & 0 deletions messages/en/lesson/en_lessonDetails.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"learningOutcome": "Learning Outcomes",
"requirements": "Requirements",
"sections": "Sections",
"mins": "mins",
"lesson": {
"title": "Lesson",
"about": "About this lesson",
Expand Down
13 changes: 13 additions & 0 deletions messages/en/organization/en_organization.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"description": "Description",
"image": "Organization Image",
"imageSize": "Image must be less than 5MB",
"lesson": "Lesson",
"classroom": "Class",
"detail": {
"noData": "No organization data available.",
"noSubscription": "No subscriptions found for this organization.",
Expand Down Expand Up @@ -244,6 +246,17 @@
"showing": "Showing",
"results": "results",
"all": "All"
},
"userTable": {
"title": "Manage Users in the Organization",
"description": "Browse and manage all organization members registered on the platform.",
"student": "Student",
"teacher": "Teacher",
"admin": "Organization Admin",
"placeholder": {
"email": "Search by email...",
"license": "Select License"
}
}
}
}
13 changes: 13 additions & 0 deletions messages/en/quiz/en_quiz.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,19 @@
"timeLimit": "Time Limit",
"mins": "mins",
"length": "Length",
"noData": "No quiz data available",
"yourFinalScore": "Your final score",
"attemptHistory": "Attempt History",
"noAttempts": "No attempts made yet.",
"startedAt": "Started At",
"completedAt": "Completed At",
"correctAnswers": "Correct Answers",
"score": "Score",
"duration": "Duration",
"status": "Status",
"resultDetail": "Result Detail",
"complete": "Completed",
"incomplete": "Incomplete",
"question": {
"question": "Question",
"singlechoice": "Single Choice",
Expand Down
6 changes: 5 additions & 1 deletion messages/vi/classroom/vi_classroom.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
"classroom": {
"list": {
"header": "Danh sách lớp học",
"description": "Quản lý tất cả các lớp học hiện có của bạn, bao gồm chi tiết lớp học, lịch trình, giáo viên và học sinh đã đăng ký.",
"searchPlaceholder": "Tìm kiếm...",
"selectCoursePlaceholder": "Chọn chương trình học",
"courses": "khóa học"
"selectStatusPlaceholder": "Lọc theo trạng thái",
"courses": "khóa học",
"noClassroom": "Không tìm thấy lớp học nào.",
"noClassroomSubtext": "Thử điều chỉnh tìm kiếm hoặc bộ lọc để tìm những gì bạn đang tìm kiếm."
},
"update": {
"basicInfo": {
Expand Down
36 changes: 33 additions & 3 deletions messages/vi/common/vi_common.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
{
"common": {
"noData": "Không tìm thấy",
"breadcrumb": {
"home": "Trang Chủ",
"course": "Khóa Học",
"courses": "Khóa Học",
"resource": "Tài Nguyên",
"lesson": "Bài Học",
"lessons": "Bài Học",
"activities": "Hoạt Động",
"courseDetail": "Chi Tiết Khóa Học",
"classroom": "Lớp Học",
"classrooms": "Lớp Học",
"classroomDetail": "Chi Tiết Lớp Học",
"createClassroom": "Tạo Lớp Học"
},
"search": {
"placeholder": "Tìm kiếm...",
"noResults": "Không tìm thấy kết quả."
Expand Down Expand Up @@ -115,7 +130,12 @@
"continueLearning": "Tiếp tục Học",
"markAsComplete": "Đánh dấu hoàn thành",
"startQuiz": "Bắt Đầu Bài Kiểm Tra",
"contact": "Liên Hệ Ngay"
"contact": "Liên Hệ Ngay",
"actions": "Thao tác",
"exportRSA": "Xuất RSA",
"exporting": "Đang Xuất...",
"downloadAndPrint": "Tải Xuống & In",
"upgrade": "Nâng Cấp Gói"
},
"message": {
"courseCreateSuccess": "Khóa học được tạo thành công!",
Expand Down Expand Up @@ -193,11 +213,20 @@
"numberOfStudents": "Số Học Sinh",
"numberOfLessons": "Số Bài Học",
"accountType": "Loại Tài Khoản",
"assignedDate": "Ngày Gán",
"assignedDate": "Ngày Tạo",
"course": "Khóa Học",
"joinedAt": "Ngày tham gia",
"subscription": "Gói đăng ký",
"student": "Học sinh"
"student": "Học sinh",
"className": "Lớp",
"user": "Người dùng",
"license": "Vai trò",
"groupName": "Nhóm",
"menu": "Mở Menu",
"score": "Điểm",
"correctAnswer": "Đáp án đúng",
"submissionDate": "Ngày nộp bài",
"studentGroup": "Nhóm học sinh"
},
"paging": {
"previous": "Trước",
Expand Down Expand Up @@ -251,6 +280,7 @@
"active": "Đã xác thực",
"inactive": "Chưa xác thực"
},

"accountType": {
"accountTypeLabel": "Loại Tài Khoản",
"admin": "Quản Trị Viên",
Expand Down
1 change: 1 addition & 0 deletions messages/vi/lesson/vi_lessonDetails.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"learningOutcome": "Mục Tiêu Học Tập",
"requirements": "Yêu Cầu",
"sections": "Chuyên mục",
"mins": "phút",
"lesson": {
"title": "Bài Học",
"about": "Giới thiệu về bài học này",
Expand Down
13 changes: 13 additions & 0 deletions messages/vi/organization/vi_organization.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"description": "Mô tả",
"image": "Ảnh tổ chức",
"imageSize": "Ảnh phải nhỏ hơn 5MB",
"lesson": "Bài học",
"classroom": "Lớp học",
"detail": {
"noData": "Không có dữ liệu tổ chức nào.",
"noSubscription": "Không có gói đăng ký nào cho tổ chức này.",
Expand Down Expand Up @@ -243,6 +245,17 @@
"showing": "Hiển thị",
"results": "kết quả",
"all": "Tất cả"
},
"userTable": {
"title": "Quản lý người dùng trong Tổ chức",
"description": "Duyệt và quản lý tất cả các thành viên tổ chức đã đăng ký trên nền tảng.",
"student": "Học sinh",
"teacher": "Giáo viên",
"admin": "Quản trị viên",
"placeholder": {
"email": "Tìm kiếm theo email...",
"license": "Chọn vai trò"
}
}
}
}
14 changes: 14 additions & 0 deletions messages/vi/quiz/vi_quiz.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,20 @@
"timeLimit": "Giới hạn thời gian",
"mins": "phút",
"length": "Độ dài",
"noData": "Không có dữ liệu quiz",
"startedAt": "Bắt đầu lúc",
"completedAt": "Kết thúc lúc",
"duration": "Thời gian thực hiện",
"status": "Trạng thái",
"correctAnswers": "Số câu đúng",
"score": "Điểm số",
"yourFinalScore": "Điểm cuối cùng của bạn",
"attemptHistory": "Lịch sử làm bài",
"submissionDate": "Ngày nộp bài",
"noAttempts": "Chưa có lần làm bài nào.",
"resultDetail": "Chi tiết kết quả",
"complete": "Hoàn thành",
"incomplete": "Chưa hoàn thành",
"question": {
"question": "Câu hỏi",
"singlechoice": "Chọn một đáp án",
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@types/three": "^0.181.0",
"@types/w3c-web-serial": "^1.0.8",
"@types/w3c-web-usb": "^1.0.13",
"autoprefixer": "^10.4.21",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ function MenuItem({

export default function AuthStatusMenu() {
const t = useTranslations('Header')
const tc = useTranslations('common')
const { data: session, status } = useSession()
const router = useRouter()
const locale = useLocale()
Expand Down Expand Up @@ -158,7 +159,7 @@ export default function AuthStatusMenu() {
onClick={() => router.push(`/${locale}/plans`)}
>
<Gem size={14} />
Upgrade
{tc('button.upgrade')}
</Button>
<LanguageSwitcher />

Expand Down
49 changes: 38 additions & 11 deletions src/components/shared/SBreadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from '@/components/shadcn/breadcrumb'
import { textVariants } from '@/utils/shadcn/variants'
import { VariantProps } from 'class-variance-authority'
import { useLocale } from 'next-intl'
import { useLocale, useTranslations } from 'next-intl'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { Fragment } from 'react'
Expand All @@ -33,15 +33,36 @@ function resolveHref(href: string): string {
return href
}

function isIdSegment(segment: string) {
return /^\d+$/.test(segment)
}

const IGNORE_SEGMENTS = ['learn', 'edit', 'view', 'preview']

export default function SBreadcrumb({ title, size = 'md', color, weight }: SBreadcrumbProps) {
const tc = useTranslations('common.breadcrumb')
const pathname = usePathname()
const locale = useLocale()
const segments = pathname
.split('/')
.filter((segment) => segment !== locale)
.filter(Boolean)
.filter(
(segment) =>
!isIdSegment(segment) && // ✅ bỏ id
!IGNORE_SEGMENTS.includes(segment) // ✅ bỏ learn
)

function formatLabel(segment: string): string {
const key = segment.replace(/-/g, '_') // nếu muốn hỗ trợ kebab-case

// thử dịch
const translated = tc(key)

// next-intl: nếu không có key -> trả về chính key
if (translated !== key) return translated

// fallback: format thủ công
return segment.replace(/-/g, ' ').replace(/\b\w/g, (char) => char.toUpperCase())
}

Expand All @@ -52,25 +73,31 @@ export default function SBreadcrumb({ title, size = 'md', color, weight }: SBrea
href
}
})
const allItems = [{ label: 'Home', href: `/${locale}` }, ...items]
const allItems = [{ label: tc('home'), href: `/${locale}` }, ...items]

return (
<Breadcrumb>
<BreadcrumbList>
{allItems.map((item) => (
{allItems.map((item, index) => (
<Fragment key={item.href}>
<BreadcrumbItem className={textVariants({ size })}>
{item.href === pathname ? (
<BreadcrumbPage className={textVariants({ color, weight })}>{title || item.label}</BreadcrumbPage>
) : (
<BreadcrumbLink asChild>
<Link href={resolveHref(item.href)}>{item.label}</Link>
</BreadcrumbLink>
)}
<BreadcrumbLink asChild>
<Link href={resolveHref(item.href)}>{item.label}</Link>
</BreadcrumbLink>
</BreadcrumbItem>
{item.href !== pathname && <BreadcrumbSeparator />}

{index < allItems.length - 1 && <BreadcrumbSeparator />}
</Fragment>
))}

{title && (
<>
<BreadcrumbSeparator />
<BreadcrumbItem className={textVariants({ size })}>
<BreadcrumbPage className={textVariants({ color, weight })}>{title}</BreadcrumbPage>
</BreadcrumbItem>
</>
)}
</BreadcrumbList>
</Breadcrumb>
)
Expand Down
Loading