Files
classroomio/src/routes/courses/[id]/people/+page.svelte
T

231 lines
7.7 KiB
Svelte
Raw Normal View History

<script lang="ts">
import { onMount } from 'svelte';
import copy from 'copy-to-clipboard';
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';
import DeleteConfirmation from '$lib/components/Course/components/People/DeleteConfirmation.svelte';
2021-08-29 07:23:19 +03:00
import {
invitationModal,
deleteMemberModal
} from '$lib/components/Course/components/People/store';
import type { Person, ProfileRole } from '$lib/components/Course/components/People/types';
import { ROLE_LABEL, ROLES } from '$lib/utils/constants/roles';
import { profile } from '$lib/utils/store/user';
import { snackbarStore } from '$lib/components/Snackbar/store';
2021-07-13 16:27:02 +00:00
export let data;
const { courseId } = data;
2021-08-24 10:45:43 +03:00
let people: Array<Person> = [];
let borderBottomGrey = 'border-r-0 border-b border-l-0 border-gray-300';
2021-08-29 07:23:19 +03:00
let member: { id?: string; email?: string; profile?: { email: string } } = {};
2021-10-10 14:05:50 +03:00
let shouldEditMemberId: string | null = null;
let filterBy: ProfileRole = ROLES[0];
2021-09-11 21:52:46 +03:00
let isStudent = false;
2021-08-29 07:23:19 +03:00
// function setPeople(people: Array<Person>) {
// if (!Array.isArray(people)) return;
// people = (people || []).sort((a, b) => a.role_id - b.role_id);
// console.log(`people changed`, people);
// }
async function deletePerson() {
$group.people = $group.people.filter((person: { id: string }) => person.id !== member.id);
2021-08-29 07:23:19 +03:00
await deleteGroupMember(member.id);
2021-08-24 10:45:43 +03:00
}
2021-08-18 19:47:02 +03:00
async function editMemberId(person: Person) {
await updatedGroupMember(
{ assigned_student_id: person.assigned_student_id },
{ id: person.id }
);
2021-10-10 14:05:50 +03:00
shouldEditMemberId = null;
}
function sortAndFilterPeople(_people: Array<Person>, filterBy: ProfileRole) {
people = (_people || [])
.filter((person) => {
if (filterBy.value === 'all') return true;
return person.role_id === filterBy.value;
})
.sort((a: Person, b: Person) => a.role_id - b.role_id);
}
2021-10-10 14:05:50 +03:00
function handleEditStudentIdMode(personId: string) {
shouldEditMemberId = personId;
}
function copyToClipboard(studentAssignedId: string | null) {
$snackbarStore.open = true;
$snackbarStore.message = `Copied to clipboard`;
if (studentAssignedId) {
copy(studentAssignedId);
}
2021-09-11 21:52:46 +03:00
}
2021-08-24 10:45:43 +03:00
onMount(async () => {
if ($course.id) return;
const { data } = await fetchCourse(courseId);
setCourse(data);
2021-08-18 19:47:02 +03:00
});
2021-08-24 10:45:43 +03:00
$: sortAndFilterPeople($group.people, filterBy);
</script>
2021-08-24 10:45:43 +03:00
<InviationModal />
2021-08-29 07:23:19 +03:00
<DeleteConfirmation
email={member.email || (member.profile && member.profile.email)}
{deletePerson}
/>
<CourseContainer bind:isStudent>
2021-08-24 10:45:43 +03:00
<PageNav title="People" disableSticky={true}>
<slot:fragment slot="widget">
2021-09-11 21:52:46 +03:00
<RoleBasedSecurity allowedRoles={[1, 2]}>
<PrimaryButton
className="mr-2"
label="Add"
onClick={() => ($invitationModal.open = true)}
/>
</RoleBasedSecurity>
2021-08-24 10:45:43 +03:00
</slot:fragment>
</PageNav>
<PageBody className="">
<div class="mb-3">
<Select
label="Filter by"
bind:value={filterBy}
options={ROLES}
2023-07-31 17:27:04 +00:00
className="flex items-center dark:text-black"
/>
</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>
2021-08-24 10:45:43 +03:00
<!-- <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>
2021-09-11 21:52:46 +03:00
<RoleBasedSecurity allowedRoles={[1, 2]}>
<p class="dark:text-white hidden lg:block text-lg w-20" />
2021-09-11 21:52:46 +03:00
</RoleBasedSecurity>
2021-08-24 10:45:43 +03:00
</div>
2021-10-10 14:05:50 +03:00
{#each people as person}
2021-09-11 21:52:46 +03:00
<div class="flex relative items-center p-3 {borderBottomGrey}">
2021-10-10 14:05:50 +03:00
{#if shouldEditMemberId === person.id}
<TextField
bind:value={person.assigned_student_id}
type="string"
placeholder="Unique ID"
2021-10-10 14:05:50 +03:00
className="w-1/4"
onChange={() => editMemberId(person)}
/>
2021-10-10 14:05:50 +03:00
{: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>
</div>
{/if}
2021-10-10 14:05:50 +03:00
</div>
{/if}
2021-08-24 10:45:43 +03:00
<!-- <span class="flex-grow" /> -->
{#if person.profile}
2021-09-11 22:15:15 +03:00
<div class="w-2/4 mx-2 flex items-center">
<Avatar src={person.profile.avatar_url} name={person.profile.fullname} />
2021-09-11 22:15:15 +03:00
<div class="ml-2 break-all">
<p class="dark:text-white text-lg">{person.profile.fullname}</p>
2021-09-11 22:15:15 +03:00
{#if !isStudent}
<a href="mailto:{person.profile.email}" class="text-md text-blue-600">
2021-09-11 22:15:15 +03:00
{person.profile.email}
</a>
{/if}
</div>
</div>
2021-08-24 10:45:43 +03:00
{: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
</p>
<a href="mailto:{person.email}" class="text-md text-blue-600">
{person.email}
</a>
</div>
2021-08-24 10:45:43 +03:00
{/if}
<p class="dark:text-white text-lg w-1/4">
{ROLE_LABEL[person.role_id]}
</p>
2021-08-29 07:23:19 +03:00
2021-09-11 21:52:46 +03:00
<RoleBasedSecurity allowedRoles={[1, 2]}>
2021-09-17 07:48:26 +03:00
<div class="hidden lg:block w-20">
2021-09-11 21:52:46 +03:00
{#if person.profile_id !== $profile.id}
<IconButton
onClick={() => {
member = person;
$deleteMemberModal.open = true;
}}
>
<TrashCanIcon size={24} class="carbon-icon dark:text-white" />
2021-09-11 21:52:46 +03:00
</IconButton>
{/if}
</div>
</RoleBasedSecurity>
2021-08-24 10:45:43 +03:00
</div>
{/each}
</div>
2021-08-24 10:45:43 +03:00
</PageBody>
</CourseContainer>
<style>
.pending {
width: fit-content;
padding: 1px 15px;
}
2021-10-10 14:05:50 +03:00
.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>