Limit functionalities by roles

This commit is contained in:
rotimi-best
2021-09-11 21:52:46 +03:00
parent 220f35b3db
commit 07eba6b4e0
14 changed files with 296 additions and 224 deletions
@@ -8,12 +8,13 @@
import CheckboxQuestion from '../../../../Question/CheckboxQuestion/index.svelte'; import CheckboxQuestion from '../../../../Question/CheckboxQuestion/index.svelte';
import TextareaQuestion from '../../../../Question/TextareaQuestion/index.svelte'; import TextareaQuestion from '../../../../Question/TextareaQuestion/index.svelte';
import PrimaryButton from '../../../../PrimaryButton/index.svelte'; import PrimaryButton from '../../../../PrimaryButton/index.svelte';
import RoleBasedSecurity from '../../../../RoleBasedSecurity/index.svelte';
import Progress from '../../../../Progress/index.svelte'; import Progress from '../../../../Progress/index.svelte';
import { removeDuplicate } from '../../../../../utils/functions/removeDuplicate'; import { removeDuplicate } from '../../../../../utils/functions/removeDuplicate';
import { QUESTION_TYPE } from '../../../../Question/constants'; import { QUESTION_TYPE } from '../../../../Question/constants';
import { STATUS } from './constants'; import { STATUS } from './constants';
import { getPropsForQuestion, filterOutDeleted } from './functions'; import { getPropsForQuestion, filterOutDeleted } from './functions';
import { formatAnswers } from '../../../function'; import { formatAnswers, getGroupMemberId } from '../../../function';
import { submitExercise } from '../../../../../utils/services/courses'; import { submitExercise } from '../../../../../utils/services/courses';
import { fetchSubmission } from '../../../../../utils/services/submissions'; import { fetchSubmission } from '../../../../../utils/services/submissions';
import { profile } from '../../../../../utils/store/user'; import { profile } from '../../../../../utils/store/user';
@@ -25,14 +26,6 @@
let renderProps = {}; let renderProps = {};
let submission; let submission;
function getGroupMemberId(people, profileId) {
const groupMember = people.find(
(person) => person.profile_id === profileId
);
return groupMember ? groupMember.id : null;
}
function handleStart() { function handleStart() {
$questionnaireMetaData.currentQuestionIndex += 1; $questionnaireMetaData.currentQuestionIndex += 1;
} }
@@ -185,8 +178,10 @@
class="w-4/5 h-40 m-auto flex items-center justify-center text-center border-2 border-gray-200 rounded-md" class="w-4/5 h-40 m-auto flex items-center justify-center text-center border-2 border-gray-200 rounded-md"
> >
<h3 class="text-2xl"> <h3 class="text-2xl">
No questions added. <br /> Click the No questions added. <br />
<span class="text-blue-700">Edit</span> button to add. <RoleBasedSecurity allowedRoles="[1,2]">
Click the <span class="text-blue-700">Edit</span> button to add.
</RoleBasedSecurity>
</h3> </h3>
</div> </div>
{:else if $questionnaireMetaData.currentQuestionIndex === 0} {:else if $questionnaireMetaData.currentQuestionIndex === 0}
@@ -9,6 +9,7 @@
} from '../store/exercise'; } from '../store/exercise';
import PrimaryButton from '../../../../PrimaryButton/index.svelte'; import PrimaryButton from '../../../../PrimaryButton/index.svelte';
import PageBody from '../../../../PageBody/index.svelte'; import PageBody from '../../../../PageBody/index.svelte';
import RoleBasedSecurity from '../../../../RoleBasedSecurity/index.svelte';
import ViewMode from './ViewMode.svelte'; import ViewMode from './ViewMode.svelte';
import EditMode from './EditMode.svelte'; import EditMode from './EditMode.svelte';
import MODES from '../../../../../utils/constants/mode.js'; import MODES from '../../../../../utils/constants/mode.js';
@@ -53,12 +54,15 @@
<PageBody> <PageBody>
<svelte:fragment slot="header"> <svelte:fragment slot="header">
<div class="flex items-center"> <div class="flex items-center">
<PrimaryButton <RoleBasedSecurity allowedRoles="[1,2]">
className="mr-2" <PrimaryButton
variant={VARIANTS.OUTLINED} className="mr-2"
label={mode === MODES.edit ? 'Save' : 'Edit'} variant={VARIANTS.OUTLINED}
onClick={handleMode} label={mode === MODES.edit ? 'Save' : 'Edit'}
/> onClick={handleMode}
/>
</RoleBasedSecurity>
<!-- {#if mode === MODES.edit || preview} --> <!-- {#if mode === MODES.edit || preview} -->
<PrimaryButton <PrimaryButton
variant={preview ? VARIANTS.CONTAINED : VARIANTS.OUTLINED} variant={preview ? VARIANTS.CONTAINED : VARIANTS.OUTLINED}
@@ -3,6 +3,7 @@
import AudioConsole32 from 'carbon-icons-svelte/lib/AudioConsole32'; import AudioConsole32 from 'carbon-icons-svelte/lib/AudioConsole32';
import Box from '../../../../Box/index.svelte'; import Box from '../../../../Box/index.svelte';
import PrimaryButton from '../../../../PrimaryButton/index.svelte'; import PrimaryButton from '../../../../PrimaryButton/index.svelte';
import RoleBasedSecurity from '../../../../RoleBasedSecurity/index.svelte';
import PageBody from '../../../../PageBody/index.svelte'; import PageBody from '../../../../PageBody/index.svelte';
import Modal from '../../../../Modal/index.svelte'; import Modal from '../../../../Modal/index.svelte';
import TextField from '../../../../Form/TextField.svelte'; import TextField from '../../../../Form/TextField.svelte';
@@ -59,8 +60,6 @@
} }
async function getExercise(exerciseId) { async function getExercise(exerciseId) {
console.log('getExercise', exerciseId);
if (!exerciseId) return; if (!exerciseId) return;
isQuestionnaireFetching.update(() => true); isQuestionnaireFetching.update(() => true);
@@ -130,11 +129,13 @@
<PageBody> <PageBody>
<slot:fragment slot="header"> <slot:fragment slot="header">
<PrimaryButton <RoleBasedSecurity allowedRoles="[1,2]">
className="mr-2" <PrimaryButton
label="Add" className="mr-2"
onClick={() => (open = !open)} label="Add"
/> onClick={() => (open = !open)}
/>
</RoleBasedSecurity>
</slot:fragment> </slot:fragment>
<div class="flex flex-wrap"> <div class="flex flex-wrap">
@@ -17,12 +17,14 @@
getLectureNo, getLectureNo,
} from '../../function'; } from '../../function';
import RoleBasedSecurity from '../../../RoleBasedSecurity/index.svelte';
import Settings from '../Settings/index.svelte'; import Settings from '../Settings/index.svelte';
import { settingsDialog } from '../Settings/store'; import { settingsDialog } from '../Settings/store';
import { lessons } from '../Lesson/store/lessons'; import { lessons } from '../Lesson/store/lessons';
import { course } from '../../store'; import { course, group } from '../../store';
import { updateCourse } from '../../../../utils/services/courses'; import { updateCourse } from '../../../../utils/services/courses';
import { profile } from '../../../../utils/store/user'; import { profile } from '../../../../utils/store/user';
import People from '../../../../routes/people.svelte';
// export let lessonId; // export let lessonId;
export let path; export let path;
@@ -92,6 +94,13 @@
label: 'Submissions', label: 'Submissions',
to: getNavItemRoute($course.id, 'submissions'), to: getNavItemRoute($course.id, 'submissions'),
hideSortIcon: true, hideSortIcon: true,
show(groupMembers = [], profileId) {
const user = groupMembers.find(
(member) => member.profile_id === profileId
);
return user ? user.role_id !== 3 : false;
},
}, },
{ {
label: 'Marks', label: 'Marks',
@@ -122,44 +131,48 @@
<Avatar src={$course.logo} /> <Avatar src={$course.logo} />
</slot:fragment> </slot:fragment>
<slot:fragment slot="widget"> <slot:fragment slot="widget">
<IconButton <RoleBasedSecurity allowedRoles="[1,2]">
onClick={() => ($settingsDialog.open = !$settingsDialog.open)} <IconButton
> onClick={() => ($settingsDialog.open = !$settingsDialog.open)}
<Settings20 class="carbon-icon" /> >
</IconButton> <Settings20 class="carbon-icon" />
</IconButton>
</RoleBasedSecurity>
</slot:fragment> </slot:fragment>
</PageNav> </PageNav>
{#each navItems as navItem} {#each navItems as navItem}
<Expandable {#if !navItem.show || (typeof navItem.show === 'function' && navItem.show($group.people, $profile.id))}
label={navItem.label} <Expandable
handleClick={handleMainGroupClick(navItem.to)} label={navItem.label}
isGroupActive={(path || $page.path) === navItem.to} handleClick={handleMainGroupClick(navItem.to)}
hideSortIcon={navItem.hideSortIcon} isGroupActive={(path || $page.path) === navItem.to}
> hideSortIcon={navItem.hideSortIcon}
{#if navItem.isLecture} >
{#each $lessons as item, index} {#if navItem.isLecture}
<a {#each $lessons as item, index}
class="item flex items-center {(path || $page.path).includes( <a
item.id class="item flex items-center {(path || $page.path).includes(
) && 'active'} pl-7 py-2 {!item.is_complete && item.id
'cursor-not-allowed'}" ) && 'active'} pl-7 py-2 {!item.is_complete &&
href={getLessonsRoute($course.id, item.id)} 'cursor-not-allowed'}"
> href={getLessonsRoute($course.id, item.id)}
<span class="course-counter"> >
{getLectureNo(index + 1)} <span class="course-counter">
</span> {getLectureNo(index + 1)}
<span>{item.title}</span>
{#if item.is_complete}
<span class="ml-2 success">
<CheckmarkFilled20 class="carbon-icon" />
</span> </span>
{:else} <span>{item.title}</span>
<span class="text-md ml-2">🔒</span> {#if item.is_complete}
{/if} <span class="ml-2 success">
</a> <CheckmarkFilled20 class="carbon-icon" />
{/each} </span>
{/if} {:else}
</Expandable> <span class="text-md ml-2">🔒</span>
{/if}
</a>
{/each}
{/if}
</Expandable>
{/if}
{/each} {/each}
<div <div
+6
View File
@@ -1,5 +1,11 @@
import { ROUTES } from './constants'; import { ROUTES } from './constants';
export function getGroupMemberId(people, profileId) {
const groupMember = people.find((person) => person.profile_id === profileId);
return groupMember ? groupMember.id : null;
}
export function getNavItemRoute(courseId, routeId) { export function getNavItemRoute(courseId, routeId) {
const path = `/${ROUTES.COURSES}/${courseId}`; const path = `/${ROUTES.COURSES}/${courseId}`;
+10 -7
View File
@@ -1,5 +1,6 @@
<script> <script>
import marked from 'marked'; import marked from 'marked';
import RoleBasedSecurity from '../RoleBasedSecurity/index.svelte';
import PageNav from '../PageNav/index.svelte'; import PageNav from '../PageNav/index.svelte';
import MODES from '../../utils/constants/mode'; import MODES from '../../utils/constants/mode';
import PrimaryButton from '../PrimaryButton/index.svelte'; import PrimaryButton from '../PrimaryButton/index.svelte';
@@ -26,13 +27,15 @@
<PageNav title="Overview" disableSticky={true}> <PageNav title="Overview" disableSticky={true}>
<svelte:fragment slot="widget"> <svelte:fragment slot="widget">
<div class="flex items-center"> <RoleBasedSecurity allowedRoles="[1,2]">
<PrimaryButton <div class="flex items-center">
className="mr-2" <PrimaryButton
label={mode === MODES.edit ? 'Save' : 'Edit'} className="mr-2"
onClick={handleModeChange} label={mode === MODES.edit ? 'Save' : 'Edit'}
/> onClick={handleModeChange}
</div> />
</div>
</RoleBasedSecurity>
</svelte:fragment> </svelte:fragment>
</PageNav> </PageNav>
@@ -0,0 +1,24 @@
<script lang="ts">
// import { ROLE } from '../../utils/constants/roles';
import { profile } from '../../utils/store/user';
import { group } from '../Course/store';
import type { Person } from '../Course/components/People/types';
export let allowedRoles: number[] = [];
let userRole: number = 0;
$: {
const user: Person = $group.people.find(
(person: { profile_id: number }) => person.profile_id === $profile.id
)!;
if (user) {
userRole = user.role_id;
}
}
</script>
{#if allowedRoles.includes(userRole)}
<slot />
{/if}
@@ -0,0 +1 @@
import { writable } from 'svelte/store';
+16 -1
View File
@@ -18,6 +18,7 @@
} from '../../../components/Course/store'; } from '../../../components/Course/store';
import { getLectureNo } from '../../../components/Course/function'; import { getLectureNo } from '../../../components/Course/function';
import { fetchCourse } from '../../../utils/services/courses'; import { fetchCourse } from '../../../utils/services/courses';
import { profile } from '../../../utils/store/user';
import { lessons } from '../../../components/Course/components/Lesson/store/lessons'; import { lessons } from '../../../components/Course/components/Lesson/store/lessons';
import { ROLE } from '../../../utils/constants/roles'; import { ROLE } from '../../../utils/constants/roles';
import { takeAttendance } from '../../../utils/services/attendance'; import { takeAttendance } from '../../../utils/services/attendance';
@@ -29,6 +30,7 @@
let borderBottomGrey = 'border-r-0 border-b border-l-0 border-gray-300'; let borderBottomGrey = 'border-r-0 border-b border-l-0 border-gray-300';
let students = []; let students = [];
let isStudent;
function setAttendance(courseData) { function setAttendance(courseData) {
for (const attendanceItem of courseData.attendance) { for (const attendanceItem of courseData.attendance) {
@@ -69,6 +71,16 @@
$: students = $group.people.filter( $: students = $group.people.filter(
(person) => !!person.profile && person.role_id === ROLE.STUDENT (person) => !!person.profile && person.role_id === ROLE.STUDENT
); );
$: {
const user = $group.people.find(
(person) => person.profile_id === $profile.id
);
if (user) {
isStudent = user.role_id === 3;
}
}
</script> </script>
<CourseContainer> <CourseContainer>
@@ -104,14 +116,17 @@
{#each $lessons as lesson} {#each $lessons as lesson}
<p class="col"> <p class="col">
<input <input
class="form-radio" class="form-radio {isStudent && 'cursor-not-allowed'}"
type="checkbox" type="checkbox"
disabled={isStudent}
checked={$attendance[student.id] checked={$attendance[student.id]
? $attendance[student.id][lesson.id] ? $attendance[student.id][lesson.id]
? $attendance[student.id][lesson.id].is_present ? $attendance[student.id][lesson.id].is_present
: false : false
: false} : false}
on:change={(e) => { on:change={(e) => {
if (isStudent) return;
const attendanceItem = $attendance[student.id] const attendanceItem = $attendance[student.id]
? $attendance[student.id][lesson.id] || {} ? $attendance[student.id][lesson.id] || {}
: {}; : {};
@@ -23,6 +23,7 @@
import CourseContainer from '../../../../../components/CourseContainer/index.svelte'; import CourseContainer from '../../../../../components/CourseContainer/index.svelte';
import PrimaryButton from '../../../../../components/PrimaryButton/index.svelte'; import PrimaryButton from '../../../../../components/PrimaryButton/index.svelte';
import RoleBasedSecurity from '../../../../../components/RoleBasedSecurity/index.svelte';
import PageNav from '../../../../../components/PageNav/index.svelte'; import PageNav from '../../../../../components/PageNav/index.svelte';
import PageBody from '../../../../../components/PageBody/index.svelte'; import PageBody from '../../../../../components/PageBody/index.svelte';
import Materials from '../../../../../components/Course/components/Lesson/Materials/index.svelte'; import Materials from '../../../../../components/Course/components/Lesson/Materials/index.svelte';
@@ -108,18 +109,20 @@
]} ]}
> >
<svelte:fragment slot="widget"> <svelte:fragment slot="widget">
{#if isMaterialsTabActive} <RoleBasedSecurity allowedRoles="[1,2]">
<div class="flex items-center"> {#if isMaterialsTabActive}
<PrimaryButton <div class="flex items-center">
className="mr-2" <PrimaryButton
label={mode === MODES.edit ? 'Save' : 'Edit'} className="mr-2"
onClick={() => { label={mode === MODES.edit ? 'Save' : 'Edit'}
prevMode = mode; onClick={() => {
mode = mode === MODES.edit ? MODES.view : MODES.edit; prevMode = mode;
}} mode = mode === MODES.edit ? MODES.view : MODES.edit;
/> }}
</div> />
{/if} </div>
{/if}
</RoleBasedSecurity>
</svelte:fragment> </svelte:fragment>
</PageNav> </PageNav>
+50 -61
View File
@@ -13,6 +13,7 @@
import Delete24 from 'carbon-icons-svelte/lib/Delete24'; import Delete24 from 'carbon-icons-svelte/lib/Delete24';
import CheckmarkFilled24 from 'carbon-icons-svelte/lib/CheckmarkFilled24'; import CheckmarkFilled24 from 'carbon-icons-svelte/lib/CheckmarkFilled24';
import PageNav from '../../../../components/PageNav/index.svelte'; import PageNav from '../../../../components/PageNav/index.svelte';
import RoleBasedSecurity from '../../../../components/RoleBasedSecurity/index.svelte';
import Box from '../../../../components/Box/index.svelte'; import Box from '../../../../components/Box/index.svelte';
import PageBody from '../../../../components/PageBody/index.svelte'; import PageBody from '../../../../components/PageBody/index.svelte';
import PrimaryButton from '../../../../components/PrimaryButton/index.svelte'; import PrimaryButton from '../../../../components/PrimaryButton/index.svelte';
@@ -38,21 +39,6 @@
let lessonEditing; let lessonEditing;
let ref; let ref;
const resources = [
{
label: 'lesson',
value: 1,
},
{
label: 'quiz',
value: 1,
},
{
label: 'home task',
value: 2,
},
];
function formatDate(date) { function formatDate(date) {
const d = new Date(date); const d = new Date(date);
@@ -87,13 +73,15 @@
<CourseContainer> <CourseContainer>
<PageNav title="Lessons"> <PageNav title="Lessons">
<div slot="widget"> <RoleBasedSecurity allowedRoles="[1,2]">
<PrimaryButton <div slot="widget">
label="Add" <PrimaryButton
onClick={addLesson} label="Add"
isDisabled={!!lessonEditing} onClick={addLesson}
/> isDisabled={!!lessonEditing}
</div> />
</div>
</RoleBasedSecurity>
</PageNav> </PageNav>
<PageBody> <PageBody>
@@ -104,42 +92,44 @@
class="group relative m-auto rounded-md border-2 border-gray-100 py-3 px-5 mb-4 flex items-center hover:shadow-2xl shadow-md transition delay-150 duration-300 ease-in-out" class="group relative m-auto rounded-md border-2 border-gray-100 py-3 px-5 mb-4 flex items-center hover:shadow-2xl shadow-md transition delay-150 duration-300 ease-in-out"
> >
<!-- Complete or Not complete icon --> <!-- Complete or Not complete icon -->
<div class="absolute -left-6 -top-6 success"> <RoleBasedSecurity allowedRoles="[1,2]">
<IconButton <div class="absolute -left-6 -top-6 success">
onClick={() => {
lesson.is_complete = !lesson.is_complete;
handleSaveLesson(lesson, $course.id);
}}
toolTipProps={{
title: `Click to ${lesson.is_complete ? 'lock' : 'unlock'}`,
direction: 'right',
}}
>
{#if lesson.is_complete}
<CheckmarkFilled24 class="carbon-icon" />
{:else}
<span class="text-2xl">🔒</span>
{/if}
</IconButton>
</div>
<!-- Edit/Save -->
<div class="absolute top-2 right-0">
{#if lessonEditing === index}
<IconButton <IconButton
onClick={() => { onClick={() => {
lessonEditing = null; lesson.is_complete = !lesson.is_complete;
handleSaveLesson(lesson, $course.id); handleSaveLesson(lesson, $course.id);
}} }}
toolTipProps={{
title: `Click to ${lesson.is_complete ? 'lock' : 'unlock'}`,
direction: 'right',
}}
> >
<Save24 class="carbon-icon" /> {#if lesson.is_complete}
<CheckmarkFilled24 class="carbon-icon" />
{:else}
<span class="text-2xl">🔒</span>
{/if}
</IconButton> </IconButton>
{:else} </div>
<IconButton onClick={() => (lessonEditing = index)}>
<Edit24 class="carbon-icon" /> <!-- Edit/Save -->
</IconButton> <div class="absolute top-2 right-0">
{/if} {#if lessonEditing === index}
</div> <IconButton
onClick={() => {
lessonEditing = null;
handleSaveLesson(lesson, $course.id);
}}
>
<Save24 class="carbon-icon" />
</IconButton>
{:else}
<IconButton onClick={() => (lessonEditing = index)}>
<Edit24 class="carbon-icon" />
</IconButton>
{/if}
</div>
</RoleBasedSecurity>
<div class=""> <div class="">
<h3 class="text-3xl font-bold">{index + 1}.</h3> <h3 class="text-3xl font-bold">{index + 1}.</h3>
@@ -173,10 +163,7 @@
{:else if !lesson.profile} {:else if !lesson.profile}
<p class="ml-2 text-sm">No tutor added</p> <p class="ml-2 text-sm">No tutor added</p>
{:else} {:else}
<a <a href="." class="flex items-center hover:underline">
href="courses/1/people"
class="flex items-center hover:underline"
>
<img <img
alt="Placeholder" alt="Placeholder"
class="block rounded-full" class="block rounded-full"
@@ -229,11 +216,13 @@
</div> </div>
</div> </div>
<div class="absolute bottom-2 right-0"> <RoleBasedSecurity allowedRoles="[1,2]">
<IconButton onClick={handleDelete(lesson.id)}> <div class="absolute bottom-2 right-0">
<Delete24 class="carbon-icon" /> <IconButton onClick={handleDelete(lesson.id)}>
</IconButton> <Delete24 class="carbon-icon" />
</div> </IconButton>
</div>
</RoleBasedSecurity>
</div> </div>
{:else} {:else}
<Box> <Box>
-2
View File
@@ -85,11 +85,9 @@
}); });
$: { $: {
// students = $group.people.filter((person) => !!person.profile);
students = $group.people.filter( students = $group.people.filter(
(person) => !!person.profile && person.role_id === ROLE.STUDENT (person) => !!person.profile && person.role_id === ROLE.STUDENT
); );
console.log(`students`, students);
} }
</script> </script>
+43 -26
View File
@@ -20,6 +20,7 @@
import Select from '../../../components/Form/Select.svelte'; import Select from '../../../components/Form/Select.svelte';
import IconButton from '../../../components/IconButton/index.svelte'; import IconButton from '../../../components/IconButton/index.svelte';
import PageBody from '../../../components/PageBody/index.svelte'; import PageBody from '../../../components/PageBody/index.svelte';
import RoleBasedSecurity from '../../../components/RoleBasedSecurity/index.svelte';
import { import {
setCourseData, setCourseData,
course, course,
@@ -45,6 +46,7 @@
let member: { id?: string; email?: string; profile?: { email: string } } = {}; let member: { id?: string; email?: string; profile?: { email: string } } = {};
let shouldEditMemberId = false; let shouldEditMemberId = false;
let filterBy: ProfileRole = ROLES[0]; let filterBy: ProfileRole = ROLES[0];
let isStudent = false;
// function setPeople(people: Array<Person>) { // function setPeople(people: Array<Person>) {
// if (!Array.isArray(people)) return; // if (!Array.isArray(people)) return;
@@ -54,8 +56,6 @@
// } // }
async function deletePerson() { async function deletePerson() {
console.log(`member`, member);
console.log(`$group.people`, $group.people);
$group.people = $group.people.filter( $group.people = $group.people.filter(
(person: { id: string }) => person.id !== member.id (person: { id: string }) => person.id !== member.id
); );
@@ -64,7 +64,6 @@
} }
async function editMemberId(person: Person) { async function editMemberId(person: Person) {
console.log(`person`, person);
await updatedGroupMember( await updatedGroupMember(
{ assigned_student_id: person.assigned_student_id }, { assigned_student_id: person.assigned_student_id },
{ id: person.id } { id: person.id }
@@ -82,6 +81,10 @@
.sort((a: Person, b: Person) => a.role_id - b.role_id); .sort((a: Person, b: Person) => a.role_id - b.role_id);
} }
function handleEditStudentIdMode() {
shouldEditMemberId = true;
}
onMount(async () => { onMount(async () => {
if ($course.id) return; if ($course.id) return;
const { data } = await fetchCourse(courseId); const { data } = await fetchCourse(courseId);
@@ -89,6 +92,15 @@
}); });
$: sortAndFilterPeople($group.people, filterBy); $: sortAndFilterPeople($group.people, filterBy);
$: {
const user: Person = $group.people.find(
(person: { profile_id: number }) => person.profile_id === $profile.id
)!;
if (user) {
isStudent = user.role_id === 3;
}
}
</script> </script>
<InviationModal /> <InviationModal />
@@ -100,11 +112,13 @@
<CourseContainer> <CourseContainer>
<PageNav title="People" disableSticky={true}> <PageNav title="People" disableSticky={true}>
<slot:fragment slot="widget"> <slot:fragment slot="widget">
<PrimaryButton <RoleBasedSecurity allowedRoles={[1, 2]}>
className="mr-2" <PrimaryButton
label="Add" className="mr-2"
onClick={() => ($invitationModal.open = true)} label="Add"
/> onClick={() => ($invitationModal.open = true)}
/>
</RoleBasedSecurity>
</slot:fragment> </slot:fragment>
</PageNav> </PageNav>
<PageBody className=""> <PageBody className="">
@@ -125,17 +139,18 @@
<!-- <span class="flex-grow" /> --> <!-- <span class="flex-grow" /> -->
<p class="text-lg w-2/4">Name</p> <p class="text-lg w-2/4">Name</p>
<p class="text-lg w-1/4 ">Role</p> <p class="text-lg w-1/4 ">Role</p>
<p class="text-lg w-20" /> <RoleBasedSecurity allowedRoles={[1, 2]}>
<p class="text-lg w-20" />
</RoleBasedSecurity>
</div> </div>
{#each people as person, index} {#each people as person, index}
<div <div class="flex relative items-center p-3 {borderBottomGrey}">
class="flex relative items-center p-3 cursor-pointer {borderBottomGrey}"
>
{#if !shouldEditMemberId} {#if !shouldEditMemberId}
<p <p
class="mr-2 w-20 text-center hover:bg-gray-100 p-3" class="mr-2 w-20 text-center {!isStudent &&
on:click={() => (shouldEditMemberId = true)} 'hover:bg-gray-100 cursor-pointer'} p-3"
on:click={() => !isStudent && handleEditStudentIdMode()}
> >
{person.assigned_student_id || '-'} {person.assigned_student_id || '-'}
</p> </p>
@@ -174,18 +189,20 @@
<p class="text-lg w-1/4 ">{ROLE_LABEL[person.role_id]}</p> <p class="text-lg w-1/4 ">{ROLE_LABEL[person.role_id]}</p>
<div class="w-20"> <RoleBasedSecurity allowedRoles={[1, 2]}>
{#if person.profile_id !== $profile.id} <div class="w-20">
<IconButton {#if person.profile_id !== $profile.id}
onClick={() => { <IconButton
member = person; onClick={() => {
$deleteMemberModal.open = true; member = person;
}} $deleteMemberModal.open = true;
> }}
<Delete24 class="carbon-icon" /> >
</IconButton> <Delete24 class="carbon-icon" />
{/if} </IconButton>
</div> {/if}
</div>
</RoleBasedSecurity>
</div> </div>
{/each} {/each}
</div> </div>
+59 -56
View File
@@ -10,6 +10,7 @@
import { dndzone } from 'svelte-dnd-action'; import { dndzone } from 'svelte-dnd-action';
import { stores, goto } from '@sapper/app'; import { stores, goto } from '@sapper/app';
import PageNav from '../../../components/PageNav/index.svelte'; import PageNav from '../../../components/PageNav/index.svelte';
import RoleBasedSecurity from '../../../components/RoleBasedSecurity/index.svelte';
import MarkExerciseModal from '../../../components/Course/components/Lesson/Exercise/MarkExerciseModal.svelte'; import MarkExerciseModal from '../../../components/Course/components/Lesson/Exercise/MarkExerciseModal.svelte';
import Chip from '../../../components/Chip/index.svelte'; import Chip from '../../../components/Chip/index.svelte';
import PageBody from '../../../components/PageBody/index.svelte'; import PageBody from '../../../components/PageBody/index.svelte';
@@ -250,69 +251,71 @@
{submissionId} {submissionId}
/> />
<CourseContainer> <RoleBasedSecurity allowedRoles="[1,2]">
<PageNav title="Submitted Exercises" /> <CourseContainer>
<PageNav title="Submitted Exercises" />
<PageBody width="w-11/12 overflow-x-auto overflow-y-hidden"> <PageBody width="w-11/12 overflow-x-auto overflow-y-hidden">
<div class="flex items-center w-full"> <div class="flex items-center w-full">
{#each sections as { id, title, items }, idx (id)} {#each sections as { id, title, items }, idx (id)}
<div
class="section rounded-md bg-gray-100 border border-gray-50 p-3 h-80 mr-3 overflow-hidden"
animate:flip={{ duration: flipDurationMs }}
>
<div class="flex items-center mb-2">
<Chip value={items.length} class="bg-set" />
<p class="ml-2 font-bold">{title}</p>
</div>
<div <div
class="content pr-2 overflow-y-auto mb-3" class="section rounded-md bg-gray-100 border border-gray-50 p-3 h-80 mr-3 overflow-hidden"
use:dndzone={{ animate:flip={{ duration: flipDurationMs }}
items,
flipDurationMs,
dropTargetStyle: { outline: 'blue' },
}}
on:consider={handleDndConsiderCards(idx)}
on:finalize={handleDndFinalizeCards(idx)}
> >
{#each items as item (item.id)} <div class="flex items-center mb-2">
<div <Chip value={items.length} class="bg-set" />
class="border border-grey-700 w-full my-2 mx-0 rounded-md bg-white py-2 px-3" <p class="ml-2 font-bold">{title}</p>
animate:flip={{ duration: flipDurationMs }} </div>
> <div
class="content pr-2 overflow-y-auto mb-3"
use:dndzone={{
items,
flipDurationMs,
dropTargetStyle: { outline: 'blue' },
}}
on:consider={handleDndConsiderCards(idx)}
on:finalize={handleDndFinalizeCards(idx)}
>
{#each items as item (item.id)}
<div <div
class="flex items-center no-underline hover:underline text-black mb-2" class="border border-grey-700 w-full my-2 mx-0 rounded-md bg-white py-2 px-3"
animate:flip={{ duration: flipDurationMs }}
> >
<img <div
alt="Student avatar" class="flex items-center no-underline hover:underline text-black mb-2"
class="block rounded-full h-6 w-6" >
src={item.student.avatar_url} <img
/> alt="Student avatar"
<p class="ml-2 text-sm">{item.student.username}</p> class="block rounded-full h-6 w-6"
src={item.student.avatar_url}
/>
<p class="ml-2 text-sm">{item.student.username}</p>
</div>
<a
class="text-blue-700 text-md font-bold"
href="{$page.path}?submissionId={item.id}"
>
{item.exercise.title}
</a>
<a
class="flex items-center no-underline hover:underline text-black my-2"
href="{$page.path.replace('submissions', 'lessons')}/{item
.lesson.id}/exercises/{item.exercise.id}"
>
<p class="text-grey text-sm">
#{item.lesson.title}
{`${item.tutor ? 'created by' + item.tutor.name : ''}`}
</p>
</a>
</div> </div>
<a {/each}
class="text-blue-700 text-md font-bold" </div>
href="{$page.path}?submissionId={item.id}"
>
{item.exercise.title}
</a>
<a
class="flex items-center no-underline hover:underline text-black my-2"
href="{$page.path.replace('submissions', 'lessons')}/{item
.lesson.id}/exercises/{item.exercise.id}"
>
<p class="text-grey text-sm">
#{item.lesson.title}
{`${item.tutor ? 'created by' + item.tutor.name : ''}`}
</p>
</a>
</div>
{/each}
</div> </div>
</div> {/each}
{/each} </div>
</div> </PageBody>
</PageBody> </CourseContainer>
</CourseContainer> </RoleBasedSecurity>
<style> <style>
.section { .section {