feat: multiple zoom accounts

This commit is contained in:
Jannat Patel
2025-05-26 18:08:17 +05:30
parent 69107d4441
commit d5b882d3f8
19 changed files with 351 additions and 63 deletions

View File

@@ -1,6 +1,6 @@
<template>
<div
class="flex flex-col border hover:border-outline-gray-4 rounded-md p-4 h-full"
class="flex flex-col border hover:border-outline-gray-3 rounded-md p-4 h-full"
style="min-height: 150px"
>
<div class="text-lg leading-5 font-semibold mb-2 text-ink-gray-9">

View File

@@ -1,6 +1,6 @@
<template>
<div
class="flex flex-col border rounded-md p-3 h-full hover:border-outline-gray-4"
class="flex flex-col border rounded-md p-3 h-full hover:border-outline-gray-3"
>
<div class="flex space-x-4 mb-4">
<div class="flex flex-col space-y-2 flex-1">

View File

@@ -1,5 +1,15 @@
<template>
<div class="flex items-center justify-between mb-5">
<div
v-if="hasPermission() && !props.zoomAccount"
class="flex items-center space-x-2 mb-5 bg-surface-amber-1 py-1 px-2 rounded-md text-ink-amber-3"
>
<AlertCircle class="size-4 stroke-1.5" />
<span>
{{ __('Please add a zoom account to the batch to create live classes.') }}
</span>
</div>
<div class="flex items-center justify-between">
<div class="text-lg font-semibold text-ink-gray-9">
{{ __('Live Class') }}
</div>
@@ -12,10 +22,10 @@
</span>
</Button>
</div>
<div v-if="liveClasses.data?.length" class="grid grid-cols-2 gap-5">
<div v-if="liveClasses.data?.length" class="grid grid-cols-2 gap-5 mt-5">
<div
v-for="cls in liveClasses.data"
class="flex flex-col border rounded-md h-full text-ink-gray-7 p-3"
class="flex flex-col border rounded-md h-full text-ink-gray-7 hover:border-outline-gray-3 p-3"
>
<div class="font-semibold text-ink-gray-9 text-lg mb-1">
{{ cls.title }}
@@ -44,7 +54,8 @@
v-if="user.data?.is_moderator || user.data?.is_evaluator"
:href="cls.start_url"
target="_blank"
class="w-1/2 cursor-pointer inline-flex items-center justify-center gap-2 transition-colors focus:outline-none text-ink-gray-8 bg-surface-gray-2 hover:bg-surface-gray-3 active:bg-surface-gray-4 focus-visible:ring focus-visible:ring-outline-gray-3 h-7 text-base px-2 rounded"
class="cursor-pointer inline-flex items-center justify-center gap-2 transition-colors focus:outline-none text-ink-gray-8 bg-surface-gray-2 hover:bg-surface-gray-3 active:bg-surface-gray-4 focus-visible:ring focus-visible:ring-outline-gray-3 h-7 text-base px-2 rounded"
:class="cls.join_url ? 'w-full' : 'w-1/2'"
>
<Monitor class="h-4 w-4 stroke-1.5" />
{{ __('Start') }}
@@ -67,21 +78,30 @@
</div>
</div>
</div>
<div v-else class="text-sm italic text-ink-gray-5">
<div v-else class="text-sm italic text-ink-gray-5 mt-2">
{{ __('No live classes scheduled') }}
</div>
<LiveClassModal
:batch="props.batch"
:zoomAccount="props.zoomAccount"
v-model="showLiveClassModal"
v-model:reloadLiveClasses="liveClasses"
/>
</template>
<script setup>
import { createListResource, Button } from 'frappe-ui'
import { Plus, Clock, Calendar, Video, Monitor, Info } from 'lucide-vue-next'
import { inject } from 'vue'
import {
Plus,
Clock,
Calendar,
Video,
Monitor,
Info,
AlertCircle,
} from 'lucide-vue-next'
import { inject, ref } from 'vue'
import LiveClassModal from '@/components/Modals/LiveClassModal.vue'
import { ref } from 'vue'
import { formatTime } from '@/utils/'
const user = inject('$user')
@@ -94,6 +114,7 @@ const props = defineProps({
type: String,
required: true,
},
zoomAccount: String,
})
const liveClasses = createListResource({
@@ -120,6 +141,11 @@ const openLiveClassModal = () => {
const canCreateClass = () => {
if (readOnlyMode) return false
if (!props.zoomAccount) return false
return hasPermission()
}
const hasPermission = () => {
return user.data?.is_moderator || user.data?.is_evaluator
}
</script>

View File

@@ -8,7 +8,7 @@
{
label: 'Submit',
variant: 'solid',
onClick: (close) => submitLiveClass(close),
onClick: ({ close }) => submitLiveClass(close),
},
],
}"
@@ -107,7 +107,11 @@ const dayjs = inject('$dayjs')
const props = defineProps({
batch: {
type: String,
default: null,
required: true,
},
zoomAccount: {
type: String,
required: true,
},
})
@@ -159,6 +163,7 @@ const createLiveClass = createResource({
return {
doctype: 'LMS Live Class',
batch_name: values.batch,
zoom_account: props.zoomAccount,
...values,
}
},
@@ -167,39 +172,11 @@ const createLiveClass = createResource({
const submitLiveClass = (close) => {
return createLiveClass.submit(liveClass, {
validate() {
if (!liveClass.title) {
return __('Please enter a title.')
}
if (!liveClass.date) {
return __('Please select a date.')
}
if (!liveClass.time) {
return __('Please select a time.')
}
if (!liveClass.timezone) {
return __('Please select a timezone.')
}
if (!valideTime()) {
return __('Please enter a valid time in the format HH:mm.')
}
const liveClassDateTime = dayjs(`${liveClass.date}T${liveClass.time}`).tz(
liveClass.timezone,
true
)
if (
liveClassDateTime.isSameOrBefore(
dayjs().tz(liveClass.timezone, false),
'minute'
)
) {
return __('Please select a future date and time.')
}
if (!liveClass.duration) {
return __('Please select a duration.')
}
validateFormFields()
},
onSuccess() {
liveClasses.value.reload()
refreshForm()
close()
},
onError(err) {
@@ -208,6 +185,39 @@ const submitLiveClass = (close) => {
})
}
const validateFormFields = () => {
if (!liveClass.title) {
return __('Please enter a title.')
}
if (!liveClass.date) {
return __('Please select a date.')
}
if (!liveClass.time) {
return __('Please select a time.')
}
if (!liveClass.timezone) {
return __('Please select a timezone.')
}
if (!valideTime()) {
return __('Please enter a valid time in the format HH:mm.')
}
const liveClassDateTime = dayjs(`${liveClass.date}T${liveClass.time}`).tz(
liveClass.timezone,
true
)
if (
liveClassDateTime.isSameOrBefore(
dayjs().tz(liveClass.timezone, false),
'minute'
)
) {
return __('Please select a future date and time.')
}
if (!liveClass.duration) {
return __('Please select a duration.')
}
}
const valideTime = () => {
let time = liveClass.time.split(':')
if (time.length != 2) {
@@ -221,4 +231,14 @@ const valideTime = () => {
}
return true
}
const refreshForm = () => {
liveClass.title = ''
liveClass.description = ''
liveClass.date = ''
liveClass.time = ''
liveClass.duration = ''
liveClass.timezone = getUserTimezone()
liveClass.auto_recording = 'No Recording'
}
</script>

View File

@@ -70,7 +70,10 @@
<BatchStudents :batch="batch" />
</div>
<div v-else-if="tab.label == 'Classes'">
<LiveClass :batch="batch.data.name" />
<LiveClass
:batch="batch.data.name"
:zoomAccount="batch.data.zoom_account"
/>
</div>
<div v-else-if="tab.label == 'Assessments'">
<Assessments :batch="batch.data.name" />

View File

@@ -159,6 +159,11 @@
}
"
/>
<Link
doctype="LMS Zoom Settings"
:label="__('Zoom Account')"
v-model="batch.zoom_account"
/>
</div>
<div class="space-y-5">
<FormControl
@@ -327,6 +332,7 @@ const batch = reactive({
paid_batch: false,
currency: '',
amount: 0,
zoom_account: '',
})
const instructors = ref([])