fix: cleanup ui
This commit is contained in:
@@ -15,13 +15,13 @@
|
||||
"markdown-it": "^14.0.0",
|
||||
"pinia": "^2.0.33",
|
||||
"socket.io-client": "^4.7.2",
|
||||
"tailwindcss": "^3.2.7",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"vue": "^3.2.25",
|
||||
"vue-chartjs": "^5.0.0",
|
||||
"vue-router": "^4.0.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^2.0.0",
|
||||
"@vitejs/plugin-vue": "^5.0.3",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"postcss": "^8.4.5",
|
||||
"vite": "^5.0.11"
|
||||
|
||||
@@ -153,8 +153,8 @@ const props = defineProps({
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background-color: theme('colors.gray.200');
|
||||
color: theme('colors.gray.700');
|
||||
background-color: theme('colors.orange.100');
|
||||
color: theme('colors.orange.600');
|
||||
}
|
||||
|
||||
.avatar-group {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="border border-gray-200 rounded-md min-w-80">
|
||||
<div class="shadow rounded-md min-w-80">
|
||||
<iframe
|
||||
v-if="course.data.video_link"
|
||||
:src="video_link"
|
||||
@@ -70,13 +70,13 @@
|
||||
<div class="mt-8 mb-4 font-medium">
|
||||
{{ __('This course has:') }}
|
||||
</div>
|
||||
<div class="flex items-center mb-4">
|
||||
<div class="flex items-center mb-3">
|
||||
<BookOpen class="h-5 w-5 stroke-1.5 text-gray-600" />
|
||||
<span class="ml-2">
|
||||
{{ course.data.lesson_count }} {{ __('Lessons') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center mb-4">
|
||||
<div class="flex items-center mb-3">
|
||||
<Users class="h-5 w-5 stroke-1.5 text-gray-600" />
|
||||
<span class="ml-2">
|
||||
{{ course.data.enrollment_count_formatted }}
|
||||
|
||||
@@ -52,10 +52,12 @@
|
||||
<script setup>
|
||||
import { Star } from 'lucide-vue-next'
|
||||
import { createResource, Button } from 'frappe-ui'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, ref, inject } from 'vue'
|
||||
import UserAvatar from '@/components/UserAvatar.vue'
|
||||
import ReviewModal from '@/components/Modals/ReviewModal.vue'
|
||||
|
||||
const user = inject('$user')
|
||||
|
||||
const props = defineProps({
|
||||
courseName: {
|
||||
type: String,
|
||||
@@ -81,12 +83,9 @@ const hasReviewed = createResource({
|
||||
owner: props.membership?.member,
|
||||
},
|
||||
},
|
||||
auto: true,
|
||||
auto: user.data?.name ? true : false,
|
||||
})
|
||||
|
||||
const reversedRange = (count) =>
|
||||
Array.from({ length: count }, (_, index) => count - index)
|
||||
|
||||
const reviews = createResource({
|
||||
url: 'lms.lms.utils.get_reviews',
|
||||
cache: ['course_reviews', props.courseName],
|
||||
@@ -96,26 +95,6 @@ const reviews = createResource({
|
||||
auto: true,
|
||||
})
|
||||
|
||||
const rating_percent = computed(() => {
|
||||
let rating_count = {}
|
||||
let rating_percent = {}
|
||||
|
||||
for (const key of [1, 2, 3, 4, 5]) {
|
||||
rating_count[key] = 0
|
||||
}
|
||||
|
||||
for (const review of reviews?.data) {
|
||||
rating_count[review.rating] += 1
|
||||
}
|
||||
|
||||
;[1, 2, 3, 4, 5].forEach((key) => {
|
||||
rating_percent[key] = (
|
||||
(rating_count[key] / reviews.data.length) *
|
||||
100
|
||||
).toFixed(2)
|
||||
})
|
||||
return rating_percent
|
||||
})
|
||||
const showReviewModal = ref(false)
|
||||
|
||||
function openReviewModal() {
|
||||
|
||||
@@ -1,34 +1,69 @@
|
||||
<template>
|
||||
<div class="flex border rounded-md p-2 mb-4 h-full">
|
||||
<div class="mr-4">
|
||||
<img
|
||||
:src="job.company_logo"
|
||||
class="w-11 h-11 rounded-lg object-contain"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex shadow rounded-md p-4 h-full">
|
||||
<img
|
||||
:src="job.company_logo"
|
||||
class="w-12 h-12 rounded-lg object-contain mr-4"
|
||||
/>
|
||||
<div>
|
||||
<div class="text-lg font-semibold mb-2">
|
||||
<div class="text-xl font-semibold mb-2">
|
||||
{{ job.job_title }}
|
||||
</div>
|
||||
<div class="flex items-center mb-2 text-gray-700">
|
||||
<div class="mr-5">
|
||||
<div>
|
||||
{{ __('posted by') }}
|
||||
<span class="font-medium">
|
||||
{{ job.company_name }}
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<MapPin class="h-4 w-4 mr-1 stroke-1.5" />
|
||||
<span class="text-gray-700">
|
||||
{{ job.location }}
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<Badge :label="job.type" theme="green" />
|
||||
<div class="ml-5">
|
||||
<div class="flex items-center my-4">
|
||||
<Badge :label="job.type" theme="green" size="lg" class="mr-4" />
|
||||
<Badge :label="job.location" theme="gray" size="lg">
|
||||
<template #prefix>
|
||||
<MapPin class="h-4 w-4 stroke-1.5" />
|
||||
</template>
|
||||
</Badge>
|
||||
</div>
|
||||
<div>
|
||||
{{ __('posted on') }}
|
||||
<span class="font-medium">
|
||||
{{ dayjs(job.creation).format('DD MMM YYYY') }}
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="flex flex-col shadow rounded-md p-4 h-full">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<div class="text-xl font-semibold mb-2">
|
||||
{{ job.job_title }}
|
||||
</div>
|
||||
<div>
|
||||
{{ __("posted by") }}
|
||||
<span class="font-medium">
|
||||
{{ job.company_name }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
:src="job.company_logo"
|
||||
class="w-12 h-12 rounded-lg object-contain"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-between mt-8">
|
||||
<div class="flex items-center">
|
||||
<Badge :label="job.type" theme="green" size="lg" class="mr-4"/>
|
||||
<Badge :label="job.location" theme="gray" size="lg">
|
||||
<template #prefix>
|
||||
<MapPin class="h-4 w-4 stroke-1.5" />
|
||||
</template>
|
||||
</Badge>
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-medium">
|
||||
{{ dayjs(job.creation).format('DD MMM YYYY') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</template>
|
||||
<script setup>
|
||||
import { MapPin } from 'lucide-vue-next'
|
||||
|
||||
@@ -1,33 +1,45 @@
|
||||
<template>
|
||||
<Dropdown :options="userDropdownOptions">
|
||||
<template v-slot="{ open }">
|
||||
<button class="flex h-12 py-2 items-center rounded-md duration-300 ease-in-out" :class="isCollapsed
|
||||
? 'px-0 w-auto'
|
||||
: open
|
||||
? 'bg-white shadow-sm px-2 w-52'
|
||||
: 'hover:bg-gray-200 px-2 w-52'
|
||||
">
|
||||
<LMSLogo class="w-8 h-8 rounded flex-shrink-0" />
|
||||
<div class="flex flex-1 flex-col text-left duration-300 ease-in-out" :class="isCollapsed
|
||||
? 'opacity-0 ml-0 w-0 overflow-hidden'
|
||||
: 'opacity-100 ml-2 w-auto'
|
||||
">
|
||||
<div class="text-base font-medium text-gray-900 leading-none">
|
||||
LMS
|
||||
</div>
|
||||
<div v-if="user" class="mt-1 text-sm text-gray-700 leading-none">
|
||||
{{ convertToTitleCase(user.split('@')[0]) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="duration-300 ease-in-out" :class="isCollapsed
|
||||
? 'opacity-0 ml-0 w-0 overflow-hidden'
|
||||
: 'opacity-100 ml-2 w-auto'
|
||||
">
|
||||
<ChevronDown class="h-4 w-4 text-gray-700" />
|
||||
</div>
|
||||
</button>
|
||||
</template>
|
||||
</Dropdown>
|
||||
<Dropdown :options="userDropdownOptions">
|
||||
<template v-slot="{ open }">
|
||||
<button
|
||||
class="flex h-12 py-2 items-center rounded-md duration-300 ease-in-out"
|
||||
:class="
|
||||
isCollapsed
|
||||
? 'px-0 w-auto'
|
||||
: open
|
||||
? 'bg-white shadow-sm px-2 w-52'
|
||||
: 'hover:bg-gray-200 px-2 w-52'
|
||||
"
|
||||
>
|
||||
<LMSLogo class="w-8 h-8 rounded flex-shrink-0" />
|
||||
<div
|
||||
class="flex flex-1 flex-col text-left duration-300 ease-in-out"
|
||||
:class="
|
||||
isCollapsed
|
||||
? 'opacity-0 ml-0 w-0 overflow-hidden'
|
||||
: 'opacity-100 ml-2 w-auto'
|
||||
"
|
||||
>
|
||||
<div class="text-base font-medium text-gray-900 leading-none">
|
||||
Learning
|
||||
</div>
|
||||
<div v-if="user" class="mt-1 text-sm text-gray-700 leading-none">
|
||||
{{ convertToTitleCase(user.split('@')[0]) }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="duration-300 ease-in-out"
|
||||
:class="
|
||||
isCollapsed
|
||||
? 'opacity-0 ml-0 w-0 overflow-hidden'
|
||||
: 'opacity-100 ml-2 w-auto'
|
||||
"
|
||||
>
|
||||
<ChevronDown class="h-4 w-4 text-gray-700" />
|
||||
</div>
|
||||
</button>
|
||||
</template>
|
||||
</Dropdown>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -37,47 +49,51 @@ import { Dropdown } from 'frappe-ui'
|
||||
import { ChevronDown } from 'lucide-vue-next'
|
||||
|
||||
const props = defineProps({
|
||||
isCollapsed: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isCollapsed: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
|
||||
const { logout, user } = sessionStore()
|
||||
let { isLoggedIn } = sessionStore();
|
||||
let { isLoggedIn } = sessionStore()
|
||||
|
||||
const userDropdownOptions = [
|
||||
{
|
||||
icon: 'log-out',
|
||||
label: 'Log out',
|
||||
onClick: () => {
|
||||
logout.submit().then(() => {
|
||||
isLoggedIn = false;
|
||||
});
|
||||
},
|
||||
condition: () => {
|
||||
return isLoggedIn
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: 'log-in',
|
||||
label: 'Log in',
|
||||
onClick: () => {
|
||||
window.location.href = '/login'
|
||||
},
|
||||
condition: () => {
|
||||
return !isLoggedIn
|
||||
}
|
||||
}
|
||||
];
|
||||
{
|
||||
icon: 'log-out',
|
||||
label: 'Log out',
|
||||
onClick: () => {
|
||||
logout.submit().then(() => {
|
||||
isLoggedIn = false
|
||||
})
|
||||
},
|
||||
condition: () => {
|
||||
return isLoggedIn
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'log-in',
|
||||
label: 'Log in',
|
||||
onClick: () => {
|
||||
window.location.href = '/login'
|
||||
},
|
||||
condition: () => {
|
||||
return !isLoggedIn
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
function convertToTitleCase(str) {
|
||||
if (!str) {
|
||||
return ""
|
||||
}
|
||||
if (!str) {
|
||||
return ''
|
||||
}
|
||||
|
||||
return str.toLowerCase().split(' ').map(function (word) {
|
||||
return word.charAt(0).toUpperCase().concat(word.substr(1));
|
||||
}).join(' ');
|
||||
return str
|
||||
.toLowerCase()
|
||||
.split(' ')
|
||||
.map(function (word) {
|
||||
return word.charAt(0).toUpperCase().concat(word.substr(1))
|
||||
})
|
||||
.join(' ')
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,27 +1,48 @@
|
||||
<template>
|
||||
<header
|
||||
class="sticky top-0 z-10 flex items-center justify-between border-b bg-white px-3 py-2.5 sm:px-5"
|
||||
>
|
||||
<Breadcrumbs
|
||||
class="h-7"
|
||||
:items="[{ label: __('Jobs'), route: { name: 'Jobs' } }]"
|
||||
/>
|
||||
<div class="flex">
|
||||
<Button v-if="user.data?.name" variant="solid">
|
||||
<template #prefix>
|
||||
<Plus class="h-4 w-4" />
|
||||
</template>
|
||||
{{ __('New Job') }}
|
||||
</Button>
|
||||
</div>
|
||||
</header>
|
||||
<div></div>
|
||||
<div class="text-base h-screen">
|
||||
<header
|
||||
class="sticky top-0 z-10 flex items-center justify-between border-b bg-white px-3 py-2.5 sm:px-5"
|
||||
>
|
||||
<Breadcrumbs
|
||||
class="h-7"
|
||||
:items="[{ label: __('Jobs'), route: { name: 'Jobs' } }]"
|
||||
/>
|
||||
<div class="flex">
|
||||
<Button v-if="user.data?.name" variant="solid">
|
||||
<template #prefix>
|
||||
<Plus class="h-4 w-4" />
|
||||
</template>
|
||||
{{ __('New Job') }}
|
||||
</Button>
|
||||
</div>
|
||||
</header>
|
||||
<div></div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import {
|
||||
createDocumentResource,
|
||||
Button,
|
||||
Breadcrumbs,
|
||||
createResource,
|
||||
} from 'frappe-ui'
|
||||
import { inject } from 'vue'
|
||||
import { Plus } from 'lucide-vue-next'
|
||||
|
||||
const user = inject('$user')
|
||||
|
||||
const props = defineProps({
|
||||
job: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
const job = createResource({
|
||||
url: 'lms.lms.api.get_job_details',
|
||||
params: {
|
||||
job: props.job,
|
||||
},
|
||||
cache: ['job'],
|
||||
auto: true,
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -41,7 +41,7 @@ import JobCard from '@/components/JobCard.vue'
|
||||
const user = inject('$user')
|
||||
|
||||
const jobs = createResource({
|
||||
url: 'lms.lms.utils.get_job_opportunities',
|
||||
url: 'lms.lms.api.get_job_opportunities',
|
||||
cache: ['jobs'],
|
||||
auto: true,
|
||||
})
|
||||
|
||||
@@ -361,12 +361,6 @@ const hideLesson = () => {
|
||||
transition: margin 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.lesson-content p {
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.7;
|
||||
|
||||
2419
frontend/yarn.lock
2419
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user