feat: timezone in batches

This commit is contained in:
Jannat Patel
2024-06-21 13:08:58 +05:30
parent 63f4dc0caa
commit 9c2bebb3d9
11 changed files with 104 additions and 29 deletions

View File

@@ -36,19 +36,25 @@
:endDate="batch.end_date" :endDate="batch.end_date"
class="mb-3" class="mb-3"
/> />
<div class="flex items-center"> <div class="flex items-center mb-3">
<Clock class="h-4 w-4 stroke-1.5 mr-2 text-gray-700" /> <Clock class="h-4 w-4 stroke-1.5 mr-2 text-gray-700" />
<span> <span>
{{ formatTime(batch.start_time) }} - {{ formatTime(batch.end_time) }} {{ formatTime(batch.start_time) }} - {{ formatTime(batch.end_time) }}
</span> </span>
</div> </div>
<div v-if="batch.timezone" class="flex items-center">
<Globe class="h-4 w-4 stroke-1.5 mr-2 text-gray-700" />
<span>
{{ batch.timezone }}
</span>
</div>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { Badge } from 'frappe-ui' import { Badge } from 'frappe-ui'
import { formatTime } from '../utils' import { formatTime } from '../utils'
import { Clock, BookOpen } from 'lucide-vue-next' import { Clock, BookOpen, Globe } from 'lucide-vue-next'
import DateRange from '@/components/Common/DateRange.vue' import DateRange from '@/components/Common/DateRange.vue'
const props = defineProps({ const props = defineProps({

View File

@@ -26,13 +26,19 @@
:endDate="batch.data.end_date" :endDate="batch.data.end_date"
class="mb-3" class="mb-3"
/> />
<div class="flex items-center"> <div class="flex items-center mb-3">
<Clock class="h-4 w-4 stroke-1.5 mr-2 text-gray-700" /> <Clock class="h-4 w-4 stroke-1.5 mr-2 text-gray-700" />
<span> <span>
{{ formatTime(batch.data.start_time) }} - {{ formatTime(batch.data.start_time) }} -
{{ formatTime(batch.data.end_time) }} {{ formatTime(batch.data.end_time) }}
</span> </span>
</div> </div>
<div v-if="batch.data.timezone" class="flex items-center">
<Globe class="h-4 w-4 stroke-1.5 mr-2 text-gray-700" />
<span>
{{ batch.data.timezone }}
</span>
</div>
<router-link <router-link
v-if="user?.data?.is_moderator" v-if="user?.data?.is_moderator"
:to="{ :to="{
@@ -91,7 +97,7 @@
<script setup> <script setup>
import { inject, computed } from 'vue' import { inject, computed } from 'vue'
import { Badge, Button } from 'frappe-ui' import { Badge, Button } from 'frappe-ui'
import { BookOpen, Clock } from 'lucide-vue-next' import { BookOpen, Clock, Globe } from 'lucide-vue-next'
import { formatNumberIntoCurrency, formatTime } from '@/utils' import { formatNumberIntoCurrency, formatTime } from '@/utils'
import DateRange from '@/components/Common/DateRange.vue' import DateRange from '@/components/Common/DateRange.vue'

View File

@@ -87,13 +87,19 @@
:endDate="batch.data.end_date" :endDate="batch.data.end_date"
class="mb-3" class="mb-3"
/> />
<div class="flex items-center mb-6"> <div class="flex items-center mb-4">
<Clock class="h-4 w-4 stroke-1.5 mr-2 text-gray-700" /> <Clock class="h-4 w-4 stroke-1.5 mr-2 text-gray-700" />
<span> <span>
{{ formatTime(batch.data.start_time) }} - {{ formatTime(batch.data.start_time) }} -
{{ formatTime(batch.data.end_time) }} {{ formatTime(batch.data.end_time) }}
</span> </span>
</div> </div>
<div v-if="batch.data.timezone" class="flex items-center mb-4">
<Globe class="h-4 w-4 stroke-1.5 mr-2 text-gray-700" />
<span>
{{ batch.data.timezone }}
</span>
</div>
</div> </div>
<AnnouncementModal <AnnouncementModal
v-model="showAnnouncementModal" v-model="showAnnouncementModal"
@@ -159,6 +165,7 @@ import {
Mail, Mail,
SendIcon, SendIcon,
MessageCircle, MessageCircle,
Globe,
} from 'lucide-vue-next' } from 'lucide-vue-next'
import { formatTime } from '@/utils' import { formatTime } from '@/utils'
import BatchDashboard from '@/components/BatchDashboard.vue' import BatchDashboard from '@/components/BatchDashboard.vue'

View File

@@ -9,30 +9,24 @@
</Button> </Button>
</header> </header>
<div class="py-5"> <div class="py-5">
<div class="container"> <div class="container border-b">
<div class="text-lg font-semibold mb-4"> <div class="text-lg font-semibold mb-4">
{{ __('Details') }} {{ __('Details') }}
</div> </div>
<div class="grid grid-cols-2 gap-10"> <div class="grid grid-cols-2 gap-10 mb-4">
<div> <div>
<FormControl <FormControl
v-model="batch.title" v-model="batch.title"
:label="__('Title')" :label="__('Title')"
class="mb-4" class="mb-4"
/> />
<FormControl
v-model="batch.description"
:label="__('Description')"
type="textarea"
class="mb-4"
/>
</div>
<div>
<FormControl <FormControl
v-model="batch.published" v-model="batch.published"
type="checkbox" type="checkbox"
:label="__('Published')" :label="__('Published')"
/> />
</div>
<div class="flex flex-col">
<FileUploader <FileUploader
v-if="!batch.image" v-if="!batch.image"
class="mt-4" class="mt-4"
@@ -52,7 +46,7 @@
</div> </div>
</template> </template>
</FileUploader> </FileUploader>
<div v-else class="mt-4"> <div v-else class="my-4">
<div class="text-xs text-gray-600 mb-1"> <div class="text-xs text-gray-600 mb-1">
{{ __('Meta Image') }} {{ __('Meta Image') }}
</div> </div>
@@ -74,10 +68,21 @@
/> />
</div> </div>
</div> </div>
<FormControl
v-model="batch.allow_self_enrollment"
type="checkbox"
:label="__('Allow self enrollment')"
/>
</div> </div>
</div> </div>
</div> </div>
<div class="container border-b mb-5"> <div class="container border-b mb-4">
<FormControl
v-model="batch.description"
:label="__('Description')"
type="textarea"
class="my-4"
/>
<div> <div>
<label class="block text-sm text-gray-600 mb-1"> <label class="block text-sm text-gray-600 mb-1">
{{ __('Batch Details') }} {{ __('Batch Details') }}
@@ -91,9 +96,9 @@
/> />
</div> </div>
</div> </div>
<div class="container border-b mb-5"> <div class="container border-b mb-4">
<div class="text-lg font-semibold mb-4"> <div class="text-lg font-semibold mb-4">
{{ __('Settings') }} {{ __('Date and Time') }}
</div> </div>
<div class="grid grid-cols-2 gap-10"> <div class="grid grid-cols-2 gap-10">
<div> <div>
@@ -109,6 +114,8 @@
type="date" type="date"
class="mb-4" class="mb-4"
/> />
</div>
<div>
<FormControl <FormControl
v-model="batch.start_time" v-model="batch.start_time"
:label="__('Start Time')" :label="__('Start Time')"
@@ -121,7 +128,20 @@
type="time" type="time"
class="mb-4" class="mb-4"
/> />
<FormControl
v-model="batch.timezone"
:label="__('Timezone')"
type="text"
class="mb-4"
/>
</div> </div>
</div>
</div>
<div class="container border-b mb-4">
<div class="text-lg font-semibold mb-4">
{{ __('Settings') }}
</div>
<div class="grid grid-cols-2 gap-10">
<div> <div>
<FormControl <FormControl
v-model="batch.seat_count" v-model="batch.seat_count"
@@ -135,6 +155,8 @@
type="date" type="date"
class="mb-4" class="mb-4"
/> />
</div>
<div>
<FormControl <FormControl
v-model="batch.medium" v-model="batch.medium"
type="select" type="select"
@@ -188,7 +210,7 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { computed, onMounted, inject, reactive } from 'vue' import { computed, onMounted, inject, reactive, onBeforeUnmount } from 'vue'
import { import {
Breadcrumbs, Breadcrumbs,
FormControl, FormControl,
@@ -221,10 +243,12 @@ const batch = reactive({
end_date: '', end_date: '',
start_time: '', start_time: '',
end_time: '', end_time: '',
timezone: '',
evaluation_end_date: '', evaluation_end_date: '',
seat_count: '', seat_count: '',
medium: '', medium: '',
category: '', category: '',
allow_self_enrollment: false,
image: null, image: null,
paid_batch: false, paid_batch: false,
currency: '', currency: '',
@@ -236,6 +260,22 @@ onMounted(() => {
if (props.batchName != 'new') { if (props.batchName != 'new') {
batchDetail.reload() batchDetail.reload()
} }
window.addEventListener('keydown', keyboardShortcut)
})
const keyboardShortcut = (e) => {
if (
e.key === 's' &&
(e.ctrlKey || e.metaKey) &&
!e.target.classList.contains('ProseMirror')
) {
saveBatch()
e.preventDefault()
}
}
onBeforeUnmount(() => {
window.removeEventListener('keydown', keyboardShortcut)
}) })
const newBatch = createResource({ const newBatch = createResource({

View File

@@ -9,14 +9,15 @@
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [ "field_order": [
"published",
"title", "title",
"start_date", "start_date",
"end_date", "end_date",
"column_break_4", "column_break_4",
"allow_self_enrollment",
"start_time", "start_time",
"end_time", "end_time",
"published", "timezone",
"allow_self_enrollment",
"section_break_rgfj", "section_break_rgfj",
"medium", "medium",
"category", "category",
@@ -301,11 +302,17 @@
"fieldname": "allow_self_enrollment", "fieldname": "allow_self_enrollment",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Allow Self Enrollment" "label": "Allow Self Enrollment"
},
{
"fieldname": "timezone",
"fieldtype": "Data",
"label": "Timezone",
"reqd": 1
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"links": [], "links": [],
"modified": "2024-05-14 14:47:48.839162", "modified": "2024-06-21 11:49:32.582832",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "LMS Batch", "name": "LMS Batch",

View File

@@ -1,5 +1,5 @@
{% set title = frappe.db.get_value("LMS Course", doc.course, "title") %} {% set title = frappe.db.get_value("LMS Course", doc.course, "title") %}
<p> {{ _("Hey {0}").format(doc.member_name) }} </p> <p> {{ _("Hey {0}").format(doc.member_name) }} </p>
<p> {{ _('Your evaluation for the course {0} has been scheduled on {1} at {2}.').format(title, frappe.utils.format_date(doc.date, "medium"), frappe.utils.format_time(doc.start_time, "short")) }}</p> <p> {{ _('Your evaluation for the course {0} has been scheduled on {1} at {2} {3}.').format(title, frappe.utils.format_date(doc.date, "medium"), frappe.utils.format_time(doc.start_time, "short")) }}, doc.timezone</p>
<p> {{ _("Please prepare well and be on time for the evaluations.") }} </p> <p> {{ _("Please prepare well and be on time for the evaluations.") }} </p>

View File

@@ -1,5 +1,5 @@
{% set title = frappe.db.get_value("LMS Course", doc.course, "title") %} {% set title = frappe.db.get_value("LMS Course", doc.course, "title") %}
<p> {{ _('Your evaluation for the course {0} has been scheduled on {1} at {2}.').format(title, frappe.utils.format_date(doc.date, "medium"), frappe.utils.format_time(doc.start_time, "short")) }}</p> <p> {{ _('Your evaluation for the course {0} has been scheduled on {1} at {2} {3}.').format(title, frappe.utils.format_date(doc.date, "medium"), frappe.utils.format_time(doc.start_time, "short")) }}, doc.timezone</p>
<p> {{ _("Please prepare well and be on time for the evaluations.") }} </p> <p> {{ _("Please prepare well and be on time for the evaluations.") }} </p>

View File

@@ -11,9 +11,9 @@
"event": "Days Before", "event": "Days Before",
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"message": "{% set title = frappe.db.get_value(\"LMS Course\", doc.course, \"title\") %}\n\n<p> {{ _('Your evaluation for the course {0} has been scheduled on {1} at {2}.').format(title, frappe.utils.format_date(doc.date, \"medium\"), frappe.utils.format_time(doc.start_time, \"short\")) }}</p>\n\n<p> {{ _(\"Please prepare well and be on time for the evaluations.\") }} </p>\n", "message": "{% set title = frappe.db.get_value(\"LMS Course\", doc.course, \"title\") %}\n\n<p> {{ _('Your evaluation for the course {0} has been scheduled on {1} at {2} {3}.').format(title, frappe.utils.format_date(doc.date, \"medium\"), frappe.utils.format_time(doc.start_time, \"short\")) }}, doc.timezone</p>\n\n<p> {{ _(\"Please prepare well and be on time for the evaluations.\") }} </p>\n",
"message_type": "HTML", "message_type": "HTML",
"modified": "2023-11-29 17:26:53.355501", "modified": "2024-06-21 12:59:05.980527",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "Certificate Request Reminder", "name": "Certificate Request Reminder",

View File

@@ -1512,6 +1512,7 @@ def get_batch_details(batch):
"paid_batch", "paid_batch",
"evaluation_end_date", "evaluation_end_date",
"allow_self_enrollment", "allow_self_enrollment",
"timezone",
], ],
as_dict=True, as_dict=True,
) )

View File

@@ -15,7 +15,7 @@
<meta name="twitter:title" content="{{ meta.title }}" /> <meta name="twitter:title" content="{{ meta.title }}" />
<meta name="twitter:image" content="{{ meta.image }}" /> <meta name="twitter:image" content="{{ meta.image }}" />
<meta name="twitter:description" content="{{ meta.description }}" /> <meta name="twitter:description" content="{{ meta.description }}" />
<script type="module" crossorigin src="/assets/lms/frontend/assets/index-kSywU9PY.js"></script> <script type="module" crossorigin src="/assets/lms/frontend/assets/index-tTMLLoXs.js"></script>
<link rel="modulepreload" crossorigin href="/assets/lms/frontend/assets/frappe-ui-vM9kBbGH.js"> <link rel="modulepreload" crossorigin href="/assets/lms/frontend/assets/frappe-ui-vM9kBbGH.js">
<link rel="stylesheet" crossorigin href="/assets/lms/frontend/assets/frappe-ui-DzKBfka9.css"> <link rel="stylesheet" crossorigin href="/assets/lms/frontend/assets/frappe-ui-DzKBfka9.css">
<link rel="stylesheet" crossorigin href="/assets/lms/frontend/assets/index-CxRhs9Fi.css"> <link rel="stylesheet" crossorigin href="/assets/lms/frontend/assets/index-CxRhs9Fi.css">

View File

@@ -82,6 +82,14 @@ def get_meta(app_path):
if re.match(r"^batches/.*$", app_path): if re.match(r"^batches/.*$", app_path):
batch_name = app_path.split("/")[1] batch_name = app_path.split("/")[1]
if "new/edit" in app_path:
return {
"title": _("New Batch"),
"image": frappe.db.get_single_value("Website Settings", "banner_image"),
"description": "Create a new batch",
"keywords": "New Batch, Create Batch",
"link": "/lms/batches/new/edit",
}
batch = frappe.db.get_value( batch = frappe.db.get_value(
"LMS Batch", "LMS Batch",
batch_name, batch_name,