CLASSROOMIO-T-97: Course UI improvement 😁😁😁
This commit is contained in:
+16
-14
@@ -22,6 +22,7 @@
|
||||
// import Footer from '$lib/components/Footer/index.svelte';
|
||||
import Apps from '$lib/components/Apps/index.svelte';
|
||||
import PlayQuiz from '$lib/components/Org/Quiz/Play/index.svelte';
|
||||
import { course } from '$lib/components/Course/store';
|
||||
import { isCoursesPage, isOrgPage, isLMSPage, isQuizPage } from '$lib/utils/functions/app';
|
||||
import showAppsSideBar from '$lib/utils/functions/showAppsSideBar';
|
||||
import isPublicRoute from '$lib/utils/functions/routes/isPublicRoute';
|
||||
@@ -71,9 +72,13 @@
|
||||
const {
|
||||
data: { session }
|
||||
} = await supabase.auth.getSession();
|
||||
const { user: authUser } = session;
|
||||
const { user: authUser } = session || {};
|
||||
console.log('Get user profile', authUser);
|
||||
|
||||
if (!authUser) {
|
||||
goto('/login');
|
||||
}
|
||||
|
||||
// Check if user has profile
|
||||
let {
|
||||
data: profileData,
|
||||
@@ -207,16 +212,13 @@
|
||||
|
||||
handleResize();
|
||||
|
||||
// if (
|
||||
// !localStorage.getItem('supabase.auth.token') &&
|
||||
// !isPublicRoute($page.url.pathname)
|
||||
// ) {
|
||||
// console.log(
|
||||
// 'No auth token and is not a public route, redirect to login',
|
||||
// path
|
||||
// );
|
||||
// return goto('/login');
|
||||
// }
|
||||
if (
|
||||
!localStorage.getItem('sb-koxqonvbkeakwvmdegcf-auth-token') &&
|
||||
!isPublicRoute($page.url.pathname)
|
||||
) {
|
||||
console.log('No auth token and is not a public route, redirect to login', path);
|
||||
return goto('/login');
|
||||
}
|
||||
|
||||
const { data: authListener } = supabase.auth.onAuthStateChange((event, session) => {
|
||||
// Log key events
|
||||
@@ -285,9 +287,9 @@
|
||||
<Moon size="60" color="#1d4ed8" unit="px" duration="1s" />
|
||||
</Backdrop>
|
||||
{/if}
|
||||
{#if !ROUTES_TO_HIDE_NAV.includes($page.url.pathname) && !isCoursesPage(path)}
|
||||
{#if isOrgPage($page.url.pathname) || $page.url.pathname.includes('profile')}
|
||||
<OrgNavigation />
|
||||
{#if !ROUTES_TO_HIDE_NAV.includes($page.url.pathname)}
|
||||
{#if isOrgPage($page.url.pathname) || $page.url.pathname.includes('profile') || isCoursesPage(path)}
|
||||
<OrgNavigation bind:title={$course.title} isCoursePage={isCoursesPage(path)} />
|
||||
{:else if isLMSPage($page.url.pathname)}
|
||||
<LMSNavigation />
|
||||
{:else}
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
type="email"
|
||||
placeholder="Enter your email.."
|
||||
className="mr-3 my-2"
|
||||
inputClassName="rounded-md"
|
||||
isRequired={true}
|
||||
isDisabled={isAdding}
|
||||
/>
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
// import { Tabs, Tab } from 'carbon-components-svelte';
|
||||
// import TabContent from 'carbon-components-svelte/src/Tabs/TabContent.svelte';
|
||||
import StudentCertificate from '$lib/components/Course/components/Ceritficate/StudentCertificate/Index.svelte';
|
||||
import { fetchCourse } from '$lib/utils/services/courses';
|
||||
|
||||
export let courseId: string = '';
|
||||
let isStudent = false;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import {
|
||||
fetchSubmissions,
|
||||
updateSubmission,
|
||||
updateQuestionAnswer,
|
||||
updateQuestionAnswer
|
||||
} from '$lib/utils/services/submissions';
|
||||
import { formatAnswers } from '$lib/components/Course/function';
|
||||
import { snackbarStore } from '$lib/components/Snackbar/store';
|
||||
@@ -33,20 +33,20 @@
|
||||
id: 1,
|
||||
title: 'Submitted',
|
||||
value: 0,
|
||||
items: [],
|
||||
items: []
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'In Progress',
|
||||
value: 0,
|
||||
items: [],
|
||||
items: []
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'Graded',
|
||||
value: 10,
|
||||
items: [],
|
||||
},
|
||||
items: []
|
||||
}
|
||||
];
|
||||
let submissionIdData = {};
|
||||
let submissionId;
|
||||
@@ -73,7 +73,7 @@
|
||||
// Update key mapping for each submission also
|
||||
submissionIdData[itemToWithNewStatus.id] = {
|
||||
...submissionIdData[itemToWithNewStatus.id],
|
||||
status_id: itemToWithNewStatus.statusId,
|
||||
status_id: itemToWithNewStatus.statusId
|
||||
};
|
||||
console.log(
|
||||
`submissionIdData[itemToWithNewStatus.id]`,
|
||||
@@ -82,7 +82,7 @@
|
||||
|
||||
updateSubmission({
|
||||
id: itemToWithNewStatus.id,
|
||||
status_id: itemToWithNewStatus.statusId,
|
||||
status_id: itemToWithNewStatus.statusId
|
||||
}).then((res) => console.log('Updated submission', res));
|
||||
}
|
||||
}
|
||||
@@ -118,24 +118,21 @@
|
||||
});
|
||||
console.log(`itemToWithNewStatus`, itemToWithNewStatus);
|
||||
// Move to right column
|
||||
sections[nextStatusId - 1].items = [
|
||||
...sections[nextStatusId - 1].items,
|
||||
itemToWithNewStatus,
|
||||
];
|
||||
sections[nextStatusId - 1].items = [...sections[nextStatusId - 1].items, itemToWithNewStatus];
|
||||
|
||||
// If something changed
|
||||
if (itemToWithNewStatus) {
|
||||
// Update key mapping for each submission also
|
||||
submissionIdData[itemToWithNewStatus.id] = {
|
||||
...submissionIdData[itemToWithNewStatus.id],
|
||||
status_id: itemToWithNewStatus.statusId,
|
||||
status_id: itemToWithNewStatus.statusId
|
||||
};
|
||||
|
||||
// Update backend
|
||||
updateSubmission({
|
||||
id: itemToWithNewStatus.id,
|
||||
status_id: itemToWithNewStatus.statusId,
|
||||
total,
|
||||
total
|
||||
}).then((res) => console.log('Updated submission', res));
|
||||
}
|
||||
}
|
||||
@@ -146,9 +143,7 @@
|
||||
let totalPoints = 0;
|
||||
|
||||
const updates = Object.keys(questionAnswerByPoint).map((questionId) => {
|
||||
const questionAnswer = questionAnswers.find(
|
||||
(answer) => answer.question_id == questionId
|
||||
);
|
||||
const questionAnswer = questionAnswers.find((answer) => answer.question_id == questionId);
|
||||
|
||||
const point = questionAnswerByPoint[questionId];
|
||||
|
||||
@@ -159,7 +154,7 @@
|
||||
|
||||
updateSubmission({
|
||||
id: submissionId,
|
||||
total: totalPoints,
|
||||
total: totalPoints
|
||||
}).then((res) => console.log('Updated submission', res));
|
||||
|
||||
$snackbarStore.open = true;
|
||||
@@ -175,21 +170,11 @@
|
||||
setCourse(data);
|
||||
}
|
||||
|
||||
const { data: submissions } = await fetchSubmissions(
|
||||
courseId || $course.id
|
||||
);
|
||||
const { data: submissions } = await fetchSubmissions(courseId || $course.id);
|
||||
const sectionById = {};
|
||||
|
||||
for (const submission of submissions) {
|
||||
const {
|
||||
id,
|
||||
created_at,
|
||||
exercise,
|
||||
course,
|
||||
answers,
|
||||
groupmember,
|
||||
status_id,
|
||||
} = submission;
|
||||
const { id, created_at, exercise, course, answers, groupmember, status_id } = submission;
|
||||
const isEarly = isSubmissionEarly(created_at, exercise.due_by);
|
||||
|
||||
const submissionItem = {
|
||||
@@ -199,14 +184,14 @@
|
||||
submittedAt: formatDate(created_at),
|
||||
exercise: {
|
||||
id: exercise.id,
|
||||
title: exercise.title,
|
||||
title: exercise.title
|
||||
},
|
||||
answers,
|
||||
student: groupmember && groupmember.profile ? groupmember.profile : {},
|
||||
lesson: {
|
||||
id: exercise.lesson.id,
|
||||
title: exercise.lesson.title,
|
||||
},
|
||||
title: exercise.lesson.title
|
||||
}
|
||||
};
|
||||
|
||||
submissionIdData[id] = {
|
||||
@@ -222,7 +207,7 @@
|
||||
acc[answer.question_id] = answer.point;
|
||||
|
||||
return acc;
|
||||
}, {}),
|
||||
}, {})
|
||||
};
|
||||
|
||||
if (Array.isArray(sectionById[status_id])) {
|
||||
@@ -234,17 +219,13 @@
|
||||
|
||||
sections = sections.map((section, index) => ({
|
||||
...section,
|
||||
value: Array.isArray(sectionById[index + 1])
|
||||
? sectionById[index + 1].length
|
||||
: 0,
|
||||
items: Array.isArray(sectionById[index + 1])
|
||||
? sectionById[index + 1]
|
||||
: [],
|
||||
value: Array.isArray(sectionById[index + 1]) ? sectionById[index + 1].length : 0,
|
||||
items: Array.isArray(sectionById[index + 1]) ? sectionById[index + 1] : []
|
||||
}));
|
||||
});
|
||||
|
||||
$: {
|
||||
const query = new URLSearchParams($page.url.search)
|
||||
const query = new URLSearchParams($page.url.search);
|
||||
submissionId = query.get('submissionId');
|
||||
openExercise = !!submissionId && submissionIdData[submissionId];
|
||||
}
|
||||
@@ -279,7 +260,7 @@
|
||||
use:dndzone={{
|
||||
items,
|
||||
flipDurationMs,
|
||||
dropTargetStyle: { outline: 'blue' },
|
||||
dropTargetStyle: { outline: 'blue' }
|
||||
}}
|
||||
on:consider={handleDndConsiderCards(idx)}
|
||||
on:finalize={handleDndFinalizeCards(idx)}
|
||||
@@ -291,11 +272,9 @@
|
||||
: 'border-red-700'} w-full my-2 mx-0 rounded-md bg-white dark:bg-gray-800 py-3 px-3"
|
||||
animate:flip={{ duration: flipDurationMs }}
|
||||
>
|
||||
<div
|
||||
class="flex items-center cursor-pointer text-black mb-2"
|
||||
on:click={() => {
|
||||
goto(`${$page.url.pathname}?submissionId=${item.id}`);
|
||||
}}
|
||||
<a
|
||||
class="flex w-full items-center cursor-pointer text-black mb-2"
|
||||
href={`${$page.url.pathname}?submissionId=${item.id}`}
|
||||
>
|
||||
<img
|
||||
alt="Student avatar"
|
||||
@@ -305,7 +284,7 @@
|
||||
<p class="dark:text-white ml-2 text-sm">
|
||||
{item.student.username}
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
class="text-blue-700 text-md font-bold"
|
||||
href="{$page.url.pathname}?submissionId={item.id}"
|
||||
@@ -314,19 +293,15 @@
|
||||
</a>
|
||||
<a
|
||||
class="flex items-center no-underline hover:underline text-black my-2"
|
||||
href="{$page.url.pathname.replace(
|
||||
'submissions',
|
||||
'lessons'
|
||||
)}/{item.lesson.id}/exercises/{item.exercise.id}"
|
||||
href="{$page.url.pathname.replace('submissions', 'lessons')}/{item.lesson
|
||||
.id}/exercises/{item.exercise.id}"
|
||||
>
|
||||
<p class="dark:text-white text-grey text-sm">
|
||||
#{item.lesson.title}
|
||||
{`${item.tutor ? 'created by' + item.tutor.name : ''}`}
|
||||
</p>
|
||||
</a>
|
||||
<p
|
||||
class="dark:text-white text-gray-500 dark:text-white text-xs"
|
||||
>
|
||||
<p class="dark:text-white text-gray-500 dark:text-white text-xs">
|
||||
{item.submittedAt}
|
||||
</p>
|
||||
<!-- <div class="badge rounded-md px-2 bg-green-500 text-white">
|
||||
|
||||
@@ -306,10 +306,9 @@
|
||||
{#if question.author.id === $profile.id}
|
||||
<PrimaryButton
|
||||
label={isEditMode ? 'Save' : 'Edit'}
|
||||
variant={VARIANTS.CONTAINED_INFO}
|
||||
variant={VARIANTS.OUTLINED}
|
||||
onClick={handleQuestionEdit}
|
||||
className="py-3 px-6 rounded-sm h-fit"
|
||||
disablePadding={true}
|
||||
className="h-fit"
|
||||
/>
|
||||
{#if isEditMode}
|
||||
<PrimaryButton
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
let {
|
||||
data: profileData,
|
||||
error,
|
||||
status,
|
||||
status
|
||||
} = await supabase.from('profile').select(`*`).eq('id', profileId).single();
|
||||
|
||||
if (error && !profileData && status === 406 && $user.currentSession) {
|
||||
@@ -47,23 +47,19 @@
|
||||
|
||||
const updates = {
|
||||
fullname: currentProfile.fullname,
|
||||
username: currentProfile.username,
|
||||
username: currentProfile.username
|
||||
};
|
||||
|
||||
if (avatar) {
|
||||
const filename = `user/${currentProfile.username + Date.now()}.webp`;
|
||||
|
||||
const { data } = await supabase.storage
|
||||
.from('avatars')
|
||||
.upload(filename, avatar, {
|
||||
cacheControl: '3600',
|
||||
upsert: false,
|
||||
});
|
||||
const { data } = await supabase.storage.from('avatars').upload(filename, avatar, {
|
||||
cacheControl: '3600',
|
||||
upsert: false
|
||||
});
|
||||
|
||||
if (data && data.Key) {
|
||||
const { publicURL } = supabase.storage
|
||||
.from('avatars')
|
||||
.getPublicUrl(filename);
|
||||
const { publicURL } = supabase.storage.from('avatars').getPublicUrl(filename);
|
||||
|
||||
updates.avatar_url = publicURL;
|
||||
currentProfile.avatar_url = publicURL;
|
||||
@@ -71,15 +67,12 @@
|
||||
avatar = undefined;
|
||||
}
|
||||
|
||||
let { error } = await supabase
|
||||
.from('profile')
|
||||
.update(updates)
|
||||
.match({ id: profileId });
|
||||
let { error } = await supabase.from('profile').update(updates).match({ id: profileId });
|
||||
|
||||
if (isOwner) {
|
||||
profile.update((_profile) => ({
|
||||
..._profile,
|
||||
...updates,
|
||||
...updates
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -117,9 +110,7 @@
|
||||
<title>Profile of {currentProfile.username}</title>
|
||||
</svelte:head>
|
||||
|
||||
<section
|
||||
class="root w-11/12 mt-3 m-auto flex items-start justify-between flex-col lg:flex-row"
|
||||
>
|
||||
<section class="root w-11/12 mt-3 m-auto flex items-start justify-between flex-col lg:flex-row">
|
||||
{#if currentProfile.id}
|
||||
<div class="w-full lg:w-1/4 flex items-center flex-col">
|
||||
<!-- <img
|
||||
@@ -129,11 +120,7 @@
|
||||
width="260"
|
||||
class="rounded-full bg-light-blue-100 mb-4"
|
||||
/> -->
|
||||
<UploadImage
|
||||
bind:avatar
|
||||
src={currentProfile.avatar_url}
|
||||
widthHeight="w-60 h-60"
|
||||
/>
|
||||
<UploadImage bind:avatar src={currentProfile.avatar_url} widthHeight="w-60 h-60" />
|
||||
|
||||
{#if isOwner}
|
||||
<TextField
|
||||
@@ -172,19 +159,16 @@
|
||||
<div class="flex-grow flex flex-wrap mx-3 w-3/5">
|
||||
<div class="mb-3 w-full">
|
||||
<h3 class="dark:text-white font-bold text-md m-0">Organizations</h3>
|
||||
<p class="dark:text-white text-gray-500 text-sm">
|
||||
This are the organizations you work at
|
||||
</p>
|
||||
<p class="dark:text-white text-gray-500 text-sm">This are the organizations you work at</p>
|
||||
|
||||
<div class="hidden my-3 py-3 px-4 border shadow-sm rounded-md">
|
||||
<h4 class="dark:text-white m-0 font-normal">
|
||||
<a class="text-blue-700 font-bold" href="/courses"> CitiBim </a>
|
||||
</h4>
|
||||
<p class="dark:text-white text-gray-500">
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Non aliquam
|
||||
tenetur magnam. Alias cumque quaerat expedita dolores placeat
|
||||
laboriosam culpa, suscipit veritatis adipisci eius magni obcaecati.
|
||||
Sequi doloremque blanditiis earum.
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Non aliquam tenetur magnam.
|
||||
Alias cumque quaerat expedita dolores placeat laboriosam culpa, suscipit veritatis
|
||||
adipisci eius magni obcaecati. Sequi doloremque blanditiis earum.
|
||||
</p>
|
||||
<div class="mt-2 flex items-center">
|
||||
<span class="flex mr-2 items-center">
|
||||
@@ -199,13 +183,11 @@
|
||||
|
||||
<div class="hidden my-2 py-3 px-4 border shadow-sm rounded-md">
|
||||
<h4 class="dark:text-white m-0 font-normal">
|
||||
<a class="text-blue-700 font-bold" href="/courses">
|
||||
Climate Change Group
|
||||
</a>
|
||||
<a class="text-blue-700 font-bold" href="/courses"> Climate Change Group </a>
|
||||
</h4>
|
||||
<p class="dark:text-white text-gray-500">
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Illo quasi
|
||||
autem quo possimus illum consequuntur repudiandae nobis error, porro
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Illo quasi autem quo possimus
|
||||
illum consequuntur repudiandae nobis error, porro
|
||||
</p>
|
||||
<div class="mt-2 flex items-center">
|
||||
<span class="flex mr-2 items-center">
|
||||
@@ -218,12 +200,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PrimaryButton
|
||||
className="px-6 py-3"
|
||||
variant={VARIANTS.CONTAINED_DANGER}
|
||||
label="Log out"
|
||||
onClick={logout}
|
||||
/>
|
||||
<PrimaryButton variant={VARIANTS.CONTAINED_DANGER} label="Log out" onClick={logout} />
|
||||
</div>
|
||||
<!-- {:else if loading}
|
||||
<Box>
|
||||
|
||||
Reference in New Issue
Block a user