CLASSROOMIO-T-83: Redesign of the People Page
CLASSROOMIO-T-83: Class Fix CLASSROOMIO-T-83: TextChip Fix CLASSROOMIO-T-83: Redesign of People Component CLASSROOMIO-T-83: Redesign of Page Component CLASSROOMIO-T-83: Add copy button for teacher CLASSROOMIO-T-83: Add copy button and show email CLASSROOMIO-T-83: Make fullname lowercase CLASSROOMIO-T-83: Fix filtering issue CLASSROOMIO-T-30:Developed the UI for the video upload CLASSROOMIO-T-30: UI cleanup CLASSROOMIO-T-30: Improve UX Merge branch 'CLASSROOMIO-T-30' of https://gitlab.com/thenextgreat/classroomio into CLASSROOMIO-T-30 CLASSROOMIO-T-30:Made the input clear after upload and also chnged the icons CLASSROOMIO-T-30: Remove console log CLASSROOMIO-T-30: Better trim out white spaces in url CLASSROOMIO-T-30:Fixed the bug between the save and edit CLASSROOMIO-T-30:Trying to fix the bug between edit and save Merge branch 'main' of https://gitlab.com/thenextgreat/classroomio CLASSROOMIO-T-30:Stil working on the reviews CLASSROOMIO-T-30:Still working on some of the reviews and updates CLASSROOMIO-T-30: Remove unnessecary values in store CLASSROOMIO-T-30: Change button to div in modal CLASSROOMIO-T-100: Select only courses belonging to current org and current user is a member CLASSROOMIO-T-100: Update condition for fetchCourses CLASSROOMIO-T-100: Select only courses belonging to current org and current user is a member Co-authored-by: Rotimi Best <rotimiibitoyeemma@gmail.com> Merge-request: CLASSROOMIO-MR-35 Merged-by: Best Admin <best@digdippa.com> Remove netlify app from redirect rule Add redirect to layout's load Redirect to about domain CLASSROOMIO-T-97: UX again? 😇 CLASSROOMIO-T-97: Better course UX 😍😍 CLASSROOMIO-T-97: Better button style and fix route not found CLASSROOMIO-T-97: Course UI improvement 😁😁😁 CLASSROOMIO-T-30: Add plyr CLASSROOMIO-T-30:Merged main into branch Merge branch 'main' of https://gitlab.com/thenextgreat/classroomio CLASSROOMIO-T-30:Wotking on the lms dashboard CLASSROOMIO-T-30:Made some changes based on the reviews Merge branch 'main' of https://gitlab.com/thenextgreat/classroomio CLASSROOMIO-T-30:Made some refactoring to keep the code DRY CLASSROOMIO-T-30:Developed the UI for the video upload Merge branch 'main' of https://gitlab.com/thenextgreat/classroomio Merge branch 'main' of https://gitlab.com/thenextgreat/classroomio CLASSROOMIO-T-27: Review Section for Instructors on landing page CLASSROOMIO-T-27: Remove unused variable Merge branch 'CLASSROOMIO-T-27' of https://gitlab.com/thenextgreat/classroomio into CLASSROOMIO-T-27 CLASSROOMIO-T-27: Complete reviews functionality CLASSROOMIO-T-27: Review Render Update CLASSROOMIO-T-27: - Resolved Feedbacks CLASSROOMIO-T-27: Fixed Ratings Data CLASSROOMIO-T-27: - Added Ratings Svg - Fixed avatar_url feedback CLASSROOMIO-T-27: Import Adjustment CLASSROOMIO-T-27: Code Review CLASSROOM-T-27: Added Add Review Functionality CLASSROOMIO-T-27: - Unresolved Review - Enhance Code Redability CLASSROOMIO-T-27: Completed the delete functionality CLASSROOMIO-T-27: Hide/Show functionality CLASSROOMIO-T-27: Double Quotation Update CLASSROOMIO-T-27: Testing toggle functinality CLASSROOMIO-T-27: Added the icons CLASSROOMIO-T-27: Completion of the hide/show functionality CLASSROOMIO-T-27: Display the store data on the review page for styling CLASSROOMIO-T-27: Styling of the review component & connecting it's data CLASSROOMIO-T-27: - Add ReviewsForm - Completion of the Reviews Form Structure/Styling CLASSROOMIO-T-27: Added a reviews modal CLASSROOMIO-T-27: Logic update for review section CLASSROOMIO-T-50: Logic for overlapping reviews CLASSROOMIO-T-27: - Completion of the structure & styling with mock data. - Addition of custom ratings assets CLASSROOMIO-T-27: - Review Section Code Structure - Import Profile Picture Assets Co-authored-by: Rotimi Best <rotimiibitoyeemma@gmail.com> Co-authored-by: Tunji Adeyemi <tunji@digdippa.com> Co-authored-by: tunny17 <tvnji17@gmail.com> Merge-request: CLASSROOMIO-MR-22 Merged-by: Best Admin <best@digdippa.com> CLASSROOMIO-T-62: Dark Mode Bug Fix CLASSROOMIO-T-62: Delete Unused class CLASSROOMIO-T-62: Dark Mode Bug Fix Co-authored-by: Tunji Adeyemi <tunji@digdippa.com> Merge-request: CLASSROOMIO-MR-23 Merged-by: Best Admin <best@digdippa.com> Co-authored-by: Ifeanyi Nwosu <ifeanyi@digdippa.com> Co-authored-by: Rotimi Best <rotimiibitoyeemma@gmail.com> Co-authored-by: Tunji Adeyemi <tunji@digdippa.com> Co-authored-by: tunny17 <tvnji17@gmail.com> Merge-request: CLASSROOMIO-MR-33 Merged-by: Best Admin <best@digdippa.com> Remove redirect from svelteapp CLASSROOMIO-T-83: Avatar fox for people page CLASSROOMIO-T-83: Search Component Test CLASSROOMIO-T-83: Redesign of the people component CLASSROOMIO-T-83: Select Box Test CLASSROOMIO-T-83: People Component Redesign Co-authored-by: Ibitoye Rotimi Best <rotimiibitoyebest@yahoo.co.uk> Co-authored-by: Rotimi Best <rotimiibitoyeemma@gmail.com> Co-authored-by: Tunji Adeyemi <tunji@digdippa.com> Co-authored-by: tunny17 <tvnji17@gmail.com> Merge-request: CLASSROOMIO-MR-36 Merged-by: Best Admin <best@digdippa.com>
This commit is contained in:
committed by
Space Cloud
co-authored by
Ibitoye Rotimi Best
Rotimi Best
Tunji Adeyemi
parent
a27bc32c63
commit
ec807a1db9
@@ -1,30 +1,30 @@
|
||||
export const ROLE = {
|
||||
ADMIN: 1,
|
||||
TUTOR: 2,
|
||||
STUDENT: 3,
|
||||
STUDENT: 3
|
||||
};
|
||||
|
||||
export const ROLE_LABEL = {
|
||||
[ROLE.ADMIN]: 'Admin',
|
||||
[ROLE.TUTOR]: 'Tutor',
|
||||
[ROLE.STUDENT]: 'Student',
|
||||
[ROLE.STUDENT]: 'Student'
|
||||
};
|
||||
|
||||
export const ROLES = [
|
||||
{
|
||||
label: 'All',
|
||||
value: 'all',
|
||||
label: 'Filter',
|
||||
value: 'all'
|
||||
},
|
||||
{
|
||||
label: ROLE_LABEL[ROLE.ADMIN],
|
||||
value: ROLE.ADMIN,
|
||||
value: ROLE.ADMIN
|
||||
},
|
||||
{
|
||||
label: ROLE_LABEL[ROLE.TUTOR],
|
||||
value: ROLE.TUTOR,
|
||||
value: ROLE.TUTOR
|
||||
},
|
||||
{
|
||||
label: ROLE_LABEL[ROLE.STUDENT],
|
||||
value: ROLE.STUDENT,
|
||||
},
|
||||
value: ROLE.STUDENT
|
||||
}
|
||||
];
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
<Checkbox disabled /> Absent
|
||||
</p>
|
||||
</div>
|
||||
<div class="dark:">
|
||||
<div>
|
||||
<Search
|
||||
class="dark:text-slate-950"
|
||||
placeholder="Search students"
|
||||
@@ -209,7 +209,6 @@
|
||||
</Box>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<Pagination totalItems={10} pageSizes={[10, 15, 20]} />
|
||||
</section>
|
||||
</CourseContainer>
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
<script lang="ts">
|
||||
import TextChip from '$lib/components/Chip/Text.svelte';
|
||||
import ComingSoon from '$lib/components/ComingSoon/index.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import copy from 'copy-to-clipboard';
|
||||
import {
|
||||
Pagination,
|
||||
CopyButton,
|
||||
Search,
|
||||
StructuredList,
|
||||
StructuredListBody,
|
||||
StructuredListCell,
|
||||
StructuredListHead,
|
||||
StructuredListRow
|
||||
} from 'carbon-components-svelte';
|
||||
import CourseContainer from '$lib/components/CourseContainer/index.svelte';
|
||||
import { fetchCourse, deleteGroupMember, updatedGroupMember } from '$lib/utils/services/courses';
|
||||
import EditIcon from 'carbon-icons-svelte/lib/Edit.svelte';
|
||||
import CopyIcon from 'carbon-icons-svelte/lib/Copy.svelte';
|
||||
import TrashCanIcon from 'carbon-icons-svelte/lib/TrashCan.svelte';
|
||||
import Avatar from '$lib/components/Avatar/index.svelte';
|
||||
import PageNav from '$lib/components/PageNav/index.svelte';
|
||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||
import TextField from '$lib/components/Form/TextField.svelte';
|
||||
import Select from '$lib/components/Form/Select.svelte';
|
||||
import IconButton from '$lib/components/IconButton/index.svelte';
|
||||
import PageBody from '$lib/components/PageBody/index.svelte';
|
||||
import RoleBasedSecurity from '$lib/components/RoleBasedSecurity/index.svelte';
|
||||
import { setCourse, course, group } from '$lib/components/Course/store';
|
||||
import InviationModal from '$lib/components/Course/components/People/InviationModal.svelte';
|
||||
@@ -25,16 +32,17 @@
|
||||
import { ROLE_LABEL, ROLES } from '$lib/utils/constants/roles';
|
||||
import { profile } from '$lib/utils/store/user';
|
||||
import { snackbarStore } from '$lib/components/Snackbar/store';
|
||||
import Avatar from '$lib/components/Avatar/index.svelte';
|
||||
|
||||
export let data;
|
||||
const { courseId } = data;
|
||||
|
||||
let people: Array<Person> = [];
|
||||
let borderBottomGrey = 'border-r-0 border-b border-l-0 border-gray-300';
|
||||
let member: { id?: string; email?: string; profile?: { email: string } } = {};
|
||||
let shouldEditMemberId: string | null = null;
|
||||
let filterBy: ProfileRole = ROLES[0];
|
||||
let isStudent = false;
|
||||
let searchValue = '';
|
||||
|
||||
// function setPeople(people: Array<Person>) {
|
||||
// if (!Array.isArray(people)) return;
|
||||
@@ -43,6 +51,15 @@
|
||||
// console.log(`people changed`, people);
|
||||
// }
|
||||
|
||||
// function for the searchbar
|
||||
function filterPeople(_query, people) {
|
||||
const query = _query.toLowerCase();
|
||||
return people.filter((person) => {
|
||||
const { profile, email } = person;
|
||||
return profile?.fullname?.toLowerCase()?.includes(query) || email?.includes(query);
|
||||
});
|
||||
}
|
||||
|
||||
async function deletePerson() {
|
||||
$group.people = $group.people.filter((person: { id: string }) => person.id !== member.id);
|
||||
|
||||
@@ -64,9 +81,16 @@
|
||||
|
||||
return person.role_id === filterBy.value;
|
||||
})
|
||||
.sort((a: Person, b: Person) => new Date(a.created_at) - new Date(b.created_at))
|
||||
.sort((a: Person, b: Person) => a.role_id - b.role_id);
|
||||
}
|
||||
|
||||
function getEmail(person) {
|
||||
const { profile, email } = person;
|
||||
|
||||
return profile ? profile.email : email;
|
||||
}
|
||||
|
||||
function handleEditStudentIdMode(personId: string) {
|
||||
shouldEditMemberId = personId;
|
||||
}
|
||||
@@ -107,124 +131,138 @@
|
||||
</RoleBasedSecurity>
|
||||
</slot:fragment>
|
||||
</PageNav>
|
||||
<PageBody className="">
|
||||
<div class="mb-3">
|
||||
<Select
|
||||
label="Filter by"
|
||||
bind:value={filterBy}
|
||||
options={ROLES}
|
||||
className="flex items-center dark:text-black"
|
||||
/>
|
||||
<section class="my-5 mx-9">
|
||||
<div class="flex flex-row flex-end justify-end items-center mb-7">
|
||||
<div class="mr-5 w-80">
|
||||
<Search
|
||||
class="dark:text-slate-950 border-0 bg-zinc-100 w-full"
|
||||
placeholder="Search people"
|
||||
bind:value={searchValue}
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<Select bind:value={filterBy} options={ROLES} className="dark:text-black mt-3 w-20" />
|
||||
<!-- <select bind:value={filterBy} class="mt-3">
|
||||
{#each ROLES as option}
|
||||
<option value={option.value}>{option.label}</option>
|
||||
{/each}
|
||||
</select> -->
|
||||
</div>
|
||||
<RoleBasedSecurity allowedRoles={[1, 2]}>
|
||||
<p class="dark:text-white hidden lg:block text-lg w-20" />
|
||||
</RoleBasedSecurity>
|
||||
</div>
|
||||
|
||||
<div class="table rounded-md border border-gray-300 w-full">
|
||||
<div class="flex items-center font-bold border-t-0 {borderBottomGrey} p-3">
|
||||
<span class="dark:text-white w-1/4 text-center">ID</span>
|
||||
<!-- <span class="flex-grow" /> -->
|
||||
<p class="dark:text-white text-lg w-2/4">Name</p>
|
||||
<p class="dark:text-white text-lg w-1/4">Role</p>
|
||||
<RoleBasedSecurity allowedRoles={[1, 2]}>
|
||||
<p class="dark:text-white hidden lg:block text-lg w-20" />
|
||||
</RoleBasedSecurity>
|
||||
</div>
|
||||
<StructuredList class="m-0">
|
||||
<StructuredListHead
|
||||
class="bg-slate-100 dark:bg-neutral-800 dark:border-2 dark:border-neutral-800"
|
||||
>
|
||||
<StructuredListRow head class="mx-7">
|
||||
<StructuredListCell head class="text-blue-700 py-3 dark:text-white"
|
||||
>Name</StructuredListCell
|
||||
>
|
||||
<StructuredListCell head class="text-blue-700 py-3 dark:text-white"
|
||||
>Role</StructuredListCell
|
||||
>
|
||||
<StructuredListCell head class="text-blue-700 py-3 dark:text-white"
|
||||
>Action</StructuredListCell
|
||||
>
|
||||
<RoleBasedSecurity allowedRoles={[1, 2]}>
|
||||
<p class="dark:text-white hidden lg:block text-lg w-20" />
|
||||
</RoleBasedSecurity>
|
||||
</StructuredListRow>
|
||||
</StructuredListHead>
|
||||
|
||||
{#each people as person}
|
||||
<div class="flex relative items-center p-3 {borderBottomGrey}">
|
||||
{#if shouldEditMemberId === person.id}
|
||||
<TextField
|
||||
bind:value={person.assigned_student_id}
|
||||
type="string"
|
||||
placeholder="Unique ID"
|
||||
className="w-1/4"
|
||||
onChange={() => editMemberId(person)}
|
||||
/>
|
||||
{:else}
|
||||
<div class="student-id flex items-center justify-between relative">
|
||||
<p class="dark:text-white w-11/12">
|
||||
{person.assigned_student_id || '-'}
|
||||
</p>
|
||||
{#if !isStudent}
|
||||
<div class="absolute edit-btn">
|
||||
<IconButton onClick={() => handleEditStudentIdMode(person.id)}>
|
||||
<EditIcon size={16} class="carbon-icon active" />
|
||||
</IconButton>
|
||||
<IconButton onClick={() => copyToClipboard(person.assigned_student_id)}>
|
||||
<CopyIcon size={16} class="carbon-icon active" />
|
||||
</IconButton>
|
||||
{#each filterPeople(searchValue, people) as person}
|
||||
<StructuredListBody>
|
||||
<StructuredListRow class="relative">
|
||||
<!-- first column -->
|
||||
<StructuredListCell class="w-3/6">
|
||||
{#if person.profile}
|
||||
<div class="flex items-center absolute bottom-3">
|
||||
<Avatar
|
||||
src={person.profile.avatar_url}
|
||||
name={person.profile.fullname}
|
||||
width="w-8"
|
||||
height="h-8"
|
||||
className="mr-3"
|
||||
/>
|
||||
<div class="flex items-center">
|
||||
<div class="mr-2">
|
||||
<p class="dark:text-white text-base font-normal">
|
||||
{person.profile.fullname}
|
||||
</p>
|
||||
<p class="text-xs text-blue-600">
|
||||
{getEmail(person)}
|
||||
</p>
|
||||
</div>
|
||||
<RoleBasedSecurity allowedRoles={[1, 2]}>
|
||||
<div class="hidden lg:flex lg:justify-between lg:items-center mr-2">
|
||||
<CopyButton text={getEmail(person)} feedback="Copied Email to clipboard" />
|
||||
</div>
|
||||
</RoleBasedSecurity>
|
||||
{#if person.profile_id == $profile.id}
|
||||
<ComingSoon label="You" />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex items-center w-2/4 absolute bottom-3">
|
||||
<TextChip
|
||||
value={person.email.substring(0, 2).toUpperCase()}
|
||||
className="bg-blue-200 text-black font-semibold text-xs mr-3"
|
||||
shape="rounded-full"
|
||||
/>
|
||||
<a
|
||||
href="mailto:{person.email}"
|
||||
class="text-md text-blue-600 mr-2 dark:text-white"
|
||||
>
|
||||
{person.email}
|
||||
</a>
|
||||
|
||||
<RoleBasedSecurity allowedRoles={[1, 2]}>
|
||||
<div class="hidden lg:flex lg:justify-between lg:items-center w-20">
|
||||
<CopyButton text={getEmail(person)} feedback="Copied Email to clipboard" />
|
||||
</div>
|
||||
</RoleBasedSecurity>
|
||||
|
||||
<TextChip
|
||||
value="Pending"
|
||||
className="text-xs bg-yellow-200 text-yellow-700 h-fit"
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<!-- <span class="flex-grow" /> -->
|
||||
{#if person.profile}
|
||||
<div class="w-2/4 mx-2 flex items-center">
|
||||
<Avatar src={person.profile.avatar_url} name={person.profile.fullname} />
|
||||
<div class="ml-2 break-all">
|
||||
<p class="dark:text-white text-lg">{person.profile.fullname}</p>
|
||||
{#if !isStudent}
|
||||
<a href="mailto:{person.profile.email}" class="text-md text-blue-600">
|
||||
{person.profile.email}
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="break-all w-2/4 mx-2">
|
||||
<p class="bg-yellow-500 pending text-sm text-center rounded-xl text-white">
|
||||
Pending Invite
|
||||
</StructuredListCell>
|
||||
|
||||
<!-- second column -->
|
||||
<StructuredListCell class="w-1/4 py-4 px-3">
|
||||
<p class="dark:text-white font-normal text-base w-1/4 my-auto">
|
||||
{ROLE_LABEL[person.role_id]}
|
||||
</p>
|
||||
<a href="mailto:{person.email}" class="text-md text-blue-600">
|
||||
{person.email}
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
</StructuredListCell>
|
||||
|
||||
<p class="dark:text-white text-lg w-1/4">
|
||||
{ROLE_LABEL[person.role_id]}
|
||||
</p>
|
||||
|
||||
<RoleBasedSecurity allowedRoles={[1, 2]}>
|
||||
<div class="hidden lg:block w-20">
|
||||
{#if person.profile_id !== $profile.id}
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
member = person;
|
||||
$deleteMemberModal.open = true;
|
||||
}}
|
||||
>
|
||||
<TrashCanIcon size={24} class="carbon-icon dark:text-white" />
|
||||
</IconButton>
|
||||
{/if}
|
||||
</div>
|
||||
</RoleBasedSecurity>
|
||||
</div>
|
||||
<!-- third column -->
|
||||
<StructuredListCell class="p-0 w-1/4">
|
||||
<RoleBasedSecurity allowedRoles={[1, 2]}>
|
||||
<div class="hidden lg:flex lg:justify-between lg:items-center w-20">
|
||||
{#if person.profile_id !== $profile.id}
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
member = person;
|
||||
$deleteMemberModal.open = true;
|
||||
}}
|
||||
>
|
||||
<TrashCanIcon size={16} class="carbon-icon dark:text-white" />
|
||||
</IconButton>
|
||||
{/if}
|
||||
</div>
|
||||
</RoleBasedSecurity>
|
||||
</StructuredListCell>
|
||||
</StructuredListRow>
|
||||
</StructuredListBody>
|
||||
{/each}
|
||||
</div>
|
||||
</PageBody>
|
||||
</StructuredList>
|
||||
<Pagination totalItems={10} pageSizes={[10, 15, 20]} />
|
||||
</section>
|
||||
</CourseContainer>
|
||||
|
||||
<style>
|
||||
.pending {
|
||||
width: fit-content;
|
||||
padding: 1px 15px;
|
||||
}
|
||||
|
||||
.student-id {
|
||||
width: 155px;
|
||||
}
|
||||
|
||||
.student-id p {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
display: none;
|
||||
}
|
||||
.student-id:hover .edit-btn {
|
||||
display: flex;
|
||||
bottom: 20px;
|
||||
right: 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user