From bcee74ce774360bfc231c047056ece246925df54 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Fri, 12 Jan 2024 21:48:42 +0530 Subject: [PATCH] feat: batch announcements --- frontend/src/App.vue | 34 ++- frontend/src/components/Annoucements.vue | 59 ++++++ frontend/src/components/AppSidebar.vue | 28 +-- frontend/src/components/BatchStudents.vue | 4 +- frontend/src/components/CourseReviews.vue | 2 +- frontend/src/components/LiveClass.vue | 2 +- frontend/src/components/MobileLayout.vue | 40 ++++ .../components/Modals/AnnouncementModal.vue | 117 +++++++++++ .../{ => Modals}/EvaluationModal.vue | 0 .../{ => Modals}/LiveClassModal.vue | 1 - .../components/{ => Modals}/ReviewModal.vue | 0 .../components/{ => Modals}/StudentModal.vue | 0 .../src/components/UpcomingEvaluations.vue | 2 +- frontend/src/pages/Batch.vue | 198 ++++++++++-------- frontend/src/utils/composables.js | 100 +++++++++ frontend/src/utils/index.js | 26 +++ 16 files changed, 489 insertions(+), 124 deletions(-) create mode 100644 frontend/src/components/Annoucements.vue create mode 100644 frontend/src/components/MobileLayout.vue create mode 100644 frontend/src/components/Modals/AnnouncementModal.vue rename frontend/src/components/{ => Modals}/EvaluationModal.vue (100%) rename frontend/src/components/{ => Modals}/LiveClassModal.vue (99%) rename frontend/src/components/{ => Modals}/ReviewModal.vue (100%) rename frontend/src/components/{ => Modals}/StudentModal.vue (100%) create mode 100644 frontend/src/utils/composables.js diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 62114a3f..b0fab586 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,13 +1,29 @@ - diff --git a/frontend/src/components/Annoucements.vue b/frontend/src/components/Annoucements.vue new file mode 100644 index 00000000..4141b688 --- /dev/null +++ b/frontend/src/components/Annoucements.vue @@ -0,0 +1,59 @@ + + + diff --git a/frontend/src/components/AppSidebar.vue b/frontend/src/components/AppSidebar.vue index 2a192cd1..917e3a0e 100644 --- a/frontend/src/components/AppSidebar.vue +++ b/frontend/src/components/AppSidebar.vue @@ -39,31 +39,11 @@ import UserDropdown from '@/components/UserDropdown.vue' import CollapseSidebar from '@/components/Icons/CollapseSidebar.vue' import SidebarLink from '@/components/SidebarLink.vue' import { useStorage } from '@vueuse/core' -import { BookOpen, Users, TrendingUp, Briefcase } from 'lucide-vue-next' -import { ref, watch } from 'vue' +import { ref } from 'vue' +import { getSidebarLinks } from '../utils' + +const links = getSidebarLinks() -const links = [ - { - label: 'Courses', - icon: BookOpen, - to: 'Courses', - }, - { - label: 'Batches', - icon: Users, - to: 'Batches', - }, - { - label: 'Statistics', - icon: TrendingUp, - to: 'Statistics', - }, - { - label: 'Jobs', - icon: Briefcase, - to: 'Jobs', - }, -] const getSidebarFromStorage = () => { return useStorage('sidebar_is_collapsed', false) } diff --git a/frontend/src/components/BatchStudents.vue b/frontend/src/components/BatchStudents.vue index 8839d064..8ef76282 100644 --- a/frontend/src/components/BatchStudents.vue +++ b/frontend/src/components/BatchStudents.vue @@ -84,9 +84,9 @@ import { Avatar, Button, } from 'frappe-ui' -import { Settings, Trash2, Plus } from 'lucide-vue-next' +import { Trash2, Plus } from 'lucide-vue-next' import { ref } from 'vue' -import StudentModal from '@/components/StudentModal.vue' +import StudentModal from '@/components/Modals/StudentModal.vue' const showStudentModal = ref(false) diff --git a/frontend/src/components/CourseReviews.vue b/frontend/src/components/CourseReviews.vue index d2440cba..6ab032c4 100644 --- a/frontend/src/components/CourseReviews.vue +++ b/frontend/src/components/CourseReviews.vue @@ -89,7 +89,7 @@ import { Star } from 'lucide-vue-next' import { createResource, Button } from 'frappe-ui' import { computed, ref } from 'vue' import UserAvatar from '@/components/UserAvatar.vue' -import ReviewModal from '@/components/ReviewModal.vue' +import ReviewModal from '@/components/Modals/ReviewModal.vue' const props = defineProps({ courseName: { diff --git a/frontend/src/components/LiveClass.vue b/frontend/src/components/LiveClass.vue index a94bc1b7..a3871a6c 100644 --- a/frontend/src/components/LiveClass.vue +++ b/frontend/src/components/LiveClass.vue @@ -70,7 +70,7 @@ import { createListResource, Button } from 'frappe-ui' import { Plus, Clock, Calendar, Video, Monitor } from 'lucide-vue-next' import { inject } from 'vue' -import LiveClassModal from '@/components/LiveClassModal.vue' +import LiveClassModal from '@/components/Modals/LiveClassModal.vue' import { ref } from 'vue' import { formatTime } from '@/utils/' diff --git a/frontend/src/components/MobileLayout.vue b/frontend/src/components/MobileLayout.vue new file mode 100644 index 00000000..985a711e --- /dev/null +++ b/frontend/src/components/MobileLayout.vue @@ -0,0 +1,40 @@ + + diff --git a/frontend/src/components/Modals/AnnouncementModal.vue b/frontend/src/components/Modals/AnnouncementModal.vue new file mode 100644 index 00000000..8d7b432e --- /dev/null +++ b/frontend/src/components/Modals/AnnouncementModal.vue @@ -0,0 +1,117 @@ + + diff --git a/frontend/src/components/EvaluationModal.vue b/frontend/src/components/Modals/EvaluationModal.vue similarity index 100% rename from frontend/src/components/EvaluationModal.vue rename to frontend/src/components/Modals/EvaluationModal.vue diff --git a/frontend/src/components/LiveClassModal.vue b/frontend/src/components/Modals/LiveClassModal.vue similarity index 99% rename from frontend/src/components/LiveClassModal.vue rename to frontend/src/components/Modals/LiveClassModal.vue index 389ad1da..044fb6be 100644 --- a/frontend/src/components/LiveClassModal.vue +++ b/frontend/src/components/Modals/LiveClassModal.vue @@ -130,7 +130,6 @@ let liveClass = reactive({ batch: props.batch, host: user.data.name, }) -console.log(liveClass) const getTimezoneOptions = () => { return getTimezones().map((timezone) => { diff --git a/frontend/src/components/ReviewModal.vue b/frontend/src/components/Modals/ReviewModal.vue similarity index 100% rename from frontend/src/components/ReviewModal.vue rename to frontend/src/components/Modals/ReviewModal.vue diff --git a/frontend/src/components/StudentModal.vue b/frontend/src/components/Modals/StudentModal.vue similarity index 100% rename from frontend/src/components/StudentModal.vue rename to frontend/src/components/Modals/StudentModal.vue diff --git a/frontend/src/components/UpcomingEvaluations.vue b/frontend/src/components/UpcomingEvaluations.vue index 86c04a10..aeb54d79 100644 --- a/frontend/src/components/UpcomingEvaluations.vue +++ b/frontend/src/components/UpcomingEvaluations.vue @@ -52,7 +52,7 @@ import { Calendar, Clock, UserCog2 } from 'lucide-vue-next' import { inject, ref } from 'vue' import { formatTime } from '../utils' import { Button, createResource } from 'frappe-ui' -import EvaluationModal from '@/components/EvaluationModal.vue' +import EvaluationModal from '@/components/Modals/EvaluationModal.vue' const dayjs = inject('$dayjs') const user = inject('$user') diff --git a/frontend/src/pages/Batch.vue b/frontend/src/pages/Batch.vue index bcadce70..b730378a 100644 --- a/frontend/src/pages/Batch.vue +++ b/frontend/src/pages/Batch.vue @@ -4,97 +4,111 @@ class="sticky top-0 z-10 flex items-center justify-between border-b bg-white px-3 py-2.5 sm:px-5" > + -
-
-
- - +
+
+
+ {{ batch.data.title }} +
+
+ + + {{ dayjs(batch.data.start_date).format('DD MMMM YYYY') }} - + {{ dayjs(batch.data.end_date).format('DD MMMM YYYY') }} + +
+
+ + + {{ formatTime(batch.data.start_time) }} - + {{ formatTime(batch.data.end_time) }} + +
+
+
+
@@ -152,6 +166,8 @@ import { Laptop, BookOpenCheck, Contact2, + Mail, + SendIcon, } from 'lucide-vue-next' import { formatTime } from '@/utils' import CourseCard from '@/components/CourseCard.vue' @@ -159,9 +175,12 @@ import BatchDashboard from '@/components/BatchDashboard.vue' import LiveClass from '@/components/LiveClass.vue' import BatchStudents from '@/components/BatchStudents.vue' import Assessments from '@/components/Assessments.vue' +import Announcements from '@/components/Annoucements.vue' +import AnnouncementModal from '@/components/Modals/AnnouncementModal.vue' const dayjs = inject('$dayjs') const user = inject('$user') +const showAnnouncementModal = ref(false) const props = defineProps({ batchName: { @@ -232,6 +251,11 @@ tabs.push({ icon: BookOpen, }) +tabs.push({ + label: 'Announcements', + icon: Mail, +}) + const courses = createResource({ url: 'lms.lms.utils.get_batch_courses', params: { @@ -244,4 +268,8 @@ const courses = createResource({ const redirectToLogin = () => { window.location.href = `/login?redirect-to=/batches` } + +const openAnnouncementModal = () => { + showAnnouncementModal.value = true +} diff --git a/frontend/src/utils/composables.js b/frontend/src/utils/composables.js new file mode 100644 index 00000000..4ef97408 --- /dev/null +++ b/frontend/src/utils/composables.js @@ -0,0 +1,100 @@ +import { onMounted, onUnmounted, reactive, ref, watch } from 'vue' + +export function useScreenSize() { + const size = reactive({ + width: window.innerWidth, + height: window.innerHeight, + }) + + const onResize = () => { + size.width = window.innerWidth + size.height = window.innerHeight + } + + onMounted(() => { + window.addEventListener('resize', onResize) + }) + + onUnmounted(() => { + window.removeEventListener('resize', onResize) + }) + + return size +} +// write a composable for detecting swipe gestures in mobile devices +export function useSwipe() { + const swipe = reactive({ + initialX: null, + initialY: null, + currentX: null, + currentY: null, + diffX: null, + diffY: null, + absDiffX: null, + absDiffY: null, + direction: null, + }) + + const onTouchStart = (e) => { + swipe.initialX = e.touches[0].clientX + swipe.initialY = e.touches[0].clientY + swipe.direction = null + swipe.diffX = null + swipe.diffY = null + swipe.absDiffX = null + swipe.absDiffY = null + } + + const onTouchMove = (e) => { + swipe.currentX = e.touches[0].clientX + swipe.currentY = e.touches[0].clientY + + swipe.diffX = swipe.initialX - swipe.currentX + swipe.diffY = swipe.initialY - swipe.currentY + + swipe.absDiffX = Math.abs(swipe.diffX) + swipe.absDiffY = Math.abs(swipe.diffY) + } + + const onTouchEnd = (e) => { + let { diffX, diffY, absDiffX, absDiffY } = swipe + if (absDiffX > absDiffY) { + if (diffX > 0) { + swipe.direction = 'left' + } else { + swipe.direction = 'right' + } + } else { + if (diffY > 0) { + swipe.direction = 'up' + } else { + swipe.direction = 'down' + } + } + } + + onMounted(() => { + window.addEventListener('touchstart', onTouchStart) + window.addEventListener('touchend', onTouchEnd) + window.addEventListener('touchmove', onTouchMove) + }) + + onUnmounted(() => { + window.removeEventListener('touchstart', onTouchStart) + window.removeEventListener('touchend', onTouchEnd) + window.removeEventListener('touchmove', onTouchMove) + }) + + return swipe +} + +export function useLocalStorage(key, initialValue) { + let value = ref(null) + let storedValue = localStorage.getItem(key) + value.value = storedValue ? JSON.parse(storedValue) : initialValue + + watch(value, (newValue) => { + localStorage.setItem(key, JSON.stringify(newValue)) + }) + return value +} diff --git a/frontend/src/utils/index.js b/frontend/src/utils/index.js index 138cea80..4e5a812a 100644 --- a/frontend/src/utils/index.js +++ b/frontend/src/utils/index.js @@ -1,5 +1,6 @@ import { toast } from 'frappe-ui' import { useDateFormat, useTimeAgo } from '@vueuse/core' +import { BookOpen, Users, TrendingUp, Briefcase } from 'lucide-vue-next' export function createToast(options) { toast({ @@ -179,3 +180,28 @@ export function getTimezones() { 'Pacific/Apia', ] } + +export function getSidebarLinks() { + return [ + { + label: 'Courses', + icon: BookOpen, + to: 'Courses', + }, + { + label: 'Batches', + icon: Users, + to: 'Batches', + }, + { + label: 'Statistics', + icon: TrendingUp, + to: 'Statistics', + }, + { + label: 'Jobs', + icon: Briefcase, + to: 'Jobs', + }, + ] +}