From c6b618130b9910f6da0d54794a2c00e6c25b6d9c Mon Sep 17 00:00:00 2001 From: TR Tajim Date: Sun, 11 Oct 2026 09:26:12 +0600 Subject: [PATCH 1/2] feat(tracker): extract SyllabusBreakdownModal and enable chapter toggling on own profile --- .../tracker/SyllabusBreakdownModal.vue | 369 ++++++++++++++++++ resources/js/pages/User/Show.vue | 235 +---------- 2 files changed, 383 insertions(+), 221 deletions(-) create mode 100644 resources/js/components/tracker/SyllabusBreakdownModal.vue diff --git a/resources/js/components/tracker/SyllabusBreakdownModal.vue b/resources/js/components/tracker/SyllabusBreakdownModal.vue new file mode 100644 index 00000000..0f304e4d --- /dev/null +++ b/resources/js/components/tracker/SyllabusBreakdownModal.vue @@ -0,0 +1,369 @@ + + + diff --git a/resources/js/pages/User/Show.vue b/resources/js/pages/User/Show.vue index 64dcbf26..14b2c852 100644 --- a/resources/js/pages/User/Show.vue +++ b/resources/js/pages/User/Show.vue @@ -42,6 +42,7 @@ import type { HeatmapItem, TrackerStats, } from '@/components/tracker/StudyHeatmap.vue'; +import SyllabusBreakdownModal from '@/components/tracker/SyllabusBreakdownModal.vue'; import SyllabusShareModal from '@/components/tracker/SyllabusShareModal.vue'; import UserListItem from '@/components/UserListItem.vue'; import VerifiedBadge from '@/components/VerifiedBadge.vue'; @@ -249,16 +250,6 @@ const isOwnProfile = computed( const showSyllabusModal = ref(false); const showShareModal = ref(false); -const showAlgorithmInfo = ref(false); -const expandedSubjects = ref>(new Set()); - -const toggleSubjectExpanded = (subjId: number) => { - if (expandedSubjects.value.has(subjId)) { - expandedSubjects.value.delete(subjId); - } else { - expandedSubjects.value.add(subjId); - } -}; const activeTab = ref<'forum' | 'blogs' | 'activity'>('forum'); const forumSubTab = ref<'questions' | 'answers'>('questions'); @@ -913,11 +904,12 @@ const formatGroupName = (group?: string) => { > Syllabus Completed ({{ syllabusProgress.course.toUpperCase() - }}) + }}{{ + syllabusProgress.group + ? ' ' + + formatGroupName(syllabusProgress.group) + : '' + }}) { - -
- -
- - -
-

- ১. অধ্যায়ের গুরুত্ব (Weight): অধ্যায়ের - পরিধি অনুযায়ী পয়েন্ট নির্ধারিত (ছোট অধ্যায় = ১ পয়েন্ট, - সাধারণ = ২ পয়েন্ট, বড় অধ্যায় = ৩ পয়েন্ট) থাকে। -

-

- ২. বিষয়ের অগ্রগতি: প্রতিটি বিষয়ের - সম্পন্ন হওয়া অধ্যায়ের মোট পয়েন্টকে ঐ বিষয়ের সর্বমোট - পয়েন্ট দিয়ে ভাগ করে শতকরা হার বের করা হয়। -

-

- ৩. সামগ্রিক অগ্রগতি (Overall): সব - বিষয়ের শতকরা অগ্রগতির সমান গড় (Average) করে মোট অগ্রগতি - বের করা হয়, যাতে কোনো বিষয়ে অধ্যায় বেশি থাকলেও ফলাফলে - বৈষম্য না ঘটে। -

-
-
- -
-
-
-
- -
-
-

- {{ subj.name }} -

-
-
- -
-
- - {{ subj.percent }}% - -

- {{ subj.completed }}/{{ subj.total }} Chapters -

-
- -
-
- - -
-
-
- - -
-
-
- - -
- - - - {{ chap.name }} - -
- - - {{ - chap.weight === 3 - ? '(Large Chapter)' - : chap.weight === 1 - ? '(Small Chapter)' - : '(Normal Chapter)' - }} - -
-
-
-
- - - + v-model="showSyllabusModal" + :user="profileUser" + :syllabus-progress="syllabusProgress" + :is-own-profile="isOwnProfile" + @share="showShareModal = true" + /> Date: Sun, 11 Oct 2026 09:59:51 +0600 Subject: [PATCH 2/2] fix(lint): remove unused imports and fix prop mutation for linter --- .../tracker/SyllabusBreakdownModal.vue | 28 +++++-------------- resources/js/pages/User/Show.vue | 4 --- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/resources/js/components/tracker/SyllabusBreakdownModal.vue b/resources/js/components/tracker/SyllabusBreakdownModal.vue index 0f304e4d..8a0b5a45 100644 --- a/resources/js/components/tracker/SyllabusBreakdownModal.vue +++ b/resources/js/components/tracker/SyllabusBreakdownModal.vue @@ -76,7 +76,9 @@ const formatGroupName = (group?: string) => { }; function toggleChapterCompletion(subj: SyllabusSubject, chap: SyllabusChapter) { - if (!props.isOwnProfile) return; + if (!props.isOwnProfile) { + return; + } const wasCompleted = chap.is_completed; chap.is_completed = !wasCompleted; @@ -90,38 +92,22 @@ function toggleChapterCompletion(subj: SyllabusSubject, chap: SyllabusChapter) { if (subj.chapters && subj.chapters.length > 0) { let totalWeight = 0; let completedWeight = 0; + for (const c of subj.chapters) { const w = c.weight || 2; totalWeight += w; + if (c.is_completed) { completedWeight += w; } } + subj.percent = totalWeight > 0 ? Math.round((completedWeight / totalWeight) * 100) : 0; } - if (props.syllabusProgress?.subjects) { - let validSubjectsCount = 0; - let totalSubjectPercents = 0; - let totalCompletedChapters = 0; - for (const s of props.syllabusProgress.subjects) { - totalCompletedChapters += s.completed; - if (s.total > 0) { - totalSubjectPercents += s.percent; - validSubjectsCount++; - } - } - if (validSubjectsCount > 0) { - props.syllabusProgress.overallPercent = Math.round( - totalSubjectPercents / validSubjectsCount, - ); - } - props.syllabusProgress.completedChapters = totalCompletedChapters; - } - router.post( `/tracker/nodes/${chap.id}/toggle`, {}, @@ -276,7 +262,7 @@ function toggleChapterCompletion(subj: SyllabusSubject, chap: SyllabusChapter) { class="flex items-center justify-between gap-2.5 px-3 py-2 text-xs transition" :class="[ isOwnProfile - ? 'cursor-pointer hover:bg-slate-100/70 active:bg-slate-200/50 select-none dark:hover:bg-gray-800/60 dark:active:bg-gray-800' + ? 'cursor-pointer select-none hover:bg-slate-100/70 active:bg-slate-200/50 dark:hover:bg-gray-800/60 dark:active:bg-gray-800' : '', ]" :role="isOwnProfile ? 'button' : undefined" diff --git a/resources/js/pages/User/Show.vue b/resources/js/pages/User/Show.vue index 14b2c852..c0ee2e1c 100644 --- a/resources/js/pages/User/Show.vue +++ b/resources/js/pages/User/Show.vue @@ -8,7 +8,6 @@ import { ArrowUpRight, Calendar, CheckCircle2, - ChevronDown, ChevronRight, Edit3, Eye, @@ -19,14 +18,12 @@ import { GraduationCap, Heart, HelpCircle, - Info, Instagram, Loader2, Lock, LogIn, MessageSquare, MessageSquareCheck, - Share2, UploadCloud, Users, X, @@ -36,7 +33,6 @@ import { computed, ref, watch } from 'vue'; import BaseModal from '@/components/BaseModal.vue'; import EmptyState from '@/components/EmptyState.vue'; import ImageViewerModal from '@/components/ImageViewerModal.vue'; -import SubjectIcon from '@/components/SubjectIcon.vue'; import StudyHeatmap from '@/components/tracker/StudyHeatmap.vue'; import type { HeatmapItem,