fix: improved UI of certified participants page

This commit is contained in:
Jannat Patel
2025-04-11 18:36:12 +05:30
parent a21020e226
commit cfbe60b731
4 changed files with 47 additions and 88 deletions

View File

@@ -1,10 +1,7 @@
<template> <template>
<div class="border rounded-md p-4"> <div class="flex flex-col border rounded-md p-4 h-full">
<div class="flex space-x-4"> <div class="flex space-x-4 mb-2">
<img <img :src="job.company_logo" class="size-8 rounded-full object-contain" />
:src="job.company_logo"
class="size-10 rounded-full object-contain"
/>
<div class="flex flex-col space-y-1 flex-1"> <div class="flex flex-col space-y-1 flex-1">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<span class="text-lg font-semibold text-ink-gray-9"> <span class="text-lg font-semibold text-ink-gray-9">
@@ -16,7 +13,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="space-x-4 mt-2"> <div class="space-x-4 mt-auto">
<Badge> <Badge>
{{ job.location }} {{ job.location }}
</Badge> </Badge>

View File

@@ -13,85 +13,36 @@
</router-link> </router-link>
</header> </header>
<div class="p-5 lg:w-3/4 mx-auto"> <div class="p-5 lg:w-3/4 mx-auto">
<div <template v-for="participant in participants.data">
class="flex flex-col lg:flex-row lg:items-center space-y-4 lg:space-y-0 justify-between mb-5" <router-link
> :to="{
<div class="text-lg text-ink-gray-9 font-semibold"> name: 'Profile',
{{ __('All Certified Participants') }} params: {
</div> username: participant.username,
<div class="grid grid-cols-2 gap-2"> },
<FormControl }"
v-model="nameFilter" >
:placeholder="__('Search by Name')" <div class="flex items-center space-x-3">
type="text" <Avatar
class="min-w-40 lg:min-w-0 lg:w-32 xl:w-40" :image="participant.user_image"
@input="updateParticipants()" class="size-8 rounded-full object-contain"
/> :label="participant.full_name"
<div size="2xl"
v-if="categories.data?.length"
class="min-w-40 lg:min-w-0 lg:w-32 xl:w-40"
>
<Select
v-model="currentCategory"
:options="categories.data"
:placeholder="__('Category')"
@change="updateParticipants()"
/> />
</div> <div>
</div> <div>
</div> {{ participant.full_name }}
<div v-if="participants.data?.length"> </div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5"> <div>
<router-link {{ participant.headline }}
v-for="participant in participants.data"
:to="{
name: 'ProfileCertificates',
params: { username: participant.username },
}"
>
<div
class="flex items-center space-x-2 border rounded-md hover:bg-surface-menu-bar p-2 text-ink-gray-7"
>
<Avatar
:image="participant.user_image"
:label="participant.full_name"
size="2xl"
/>
<div class="flex flex-col space-y-2">
<div class="font-medium">
{{ participant.full_name }}
</div>
<div
v-if="participant.headline"
class="headline text-sm text-ink-gray-7"
>
{{ participant.headline }}
</div>
</div> </div>
</div> </div>
</router-link> <div>
</div> {{ participant.certificate_count }} {{ __('certificates') }}
<div </div>
v-if="!participants.list.loading && participants.hasNextPage" </div>
class="flex justify-center mt-5" </router-link>
> </template>
<Button @click="participants.next()">
{{ __('Load More') }}
</Button>
</div>
</div>
<div
v-else-if="!participants.list.loading"
class="flex flex-col items-center justify-center text-sm text-ink-gray-5 italic mt-48"
>
<BookOpen class="size-10 mx-auto stroke-1 text-ink-gray-4" />
<div class="text-lg font-medium mb-1">
{{ __('No participants found') }}
</div>
<div class="leading-5 w-2/5 text-center">
{{ __('There are no participants matching this criteria.') }}
</div>
</div>
</div> </div>
</template> </template>
<script setup> <script setup>
@@ -126,6 +77,10 @@ const participants = createListResource({
pageLength: 30, pageLength: 30,
}) })
const count = call('lms.lms.api.get_count_of_certified_members').then(
(data) => {}
)
const categories = createListResource({ const categories = createListResource({
doctype: 'LMS Certificate', doctype: 'LMS Certificate',
url: 'lms.lms.api.get_certification_categories', url: 'lms.lms.api.get_certification_categories',

View File

@@ -411,13 +411,13 @@ def get_certified_participants(filters=None, start=0, page_length=30):
or_filters["course_title"] = ["like", f"%{category}%"] or_filters["course_title"] = ["like", f"%{category}%"]
or_filters["batch_title"] = ["like", f"%{category}%"] or_filters["batch_title"] = ["like", f"%{category}%"]
participants = frappe.get_all( participants = frappe.db.get_all(
"LMS Certificate", "LMS Certificate",
filters=filters, filters=filters,
or_filters=or_filters, or_filters=or_filters,
fields=["member"], fields=["member", "COUNT(*) as certificate_count"],
group_by="member", group_by="member",
order_by="creation desc", order_by="MAX(creation) desc",
start=start, start=start,
page_length=page_length, page_length=page_length,
) )

View File

@@ -28,7 +28,7 @@ def get_context():
def get_meta(app_path, title, favicon, description): def get_meta(app_path, title, favicon, description):
meta = {} meta = frappe._dict()
if app_path: if app_path:
meta = get_meta_from_document(app_path) meta = get_meta_from_document(app_path)
@@ -46,7 +46,7 @@ def get_meta(app_path, title, favicon, description):
meta["keywords"] = f"{meta.get('keywords', '')} {row.value}" meta["keywords"] = f"{meta.get('keywords', '')} {row.value}"
elif row.key == "link": elif row.key == "link":
meta["link"] = row.value meta["link"] = row.value
print(meta)
if not meta.get("description"): if not meta.get("description"):
meta["description"] = description meta["description"] = description
@@ -273,3 +273,10 @@ def get_meta_from_document(app_path):
"keywords": "All Programs, Programs, Learn", "keywords": "All Programs, Programs, Learn",
"link": "/programs", "link": "/programs",
} }
if app_path == "certified-participants":
return {
"title": _("Certified Participants"),
"keywords": "All Certified Participants, Certified Participants, Learn, Certification",
"link": "/certified-participants",
}