Limit functionalities by roles
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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}`;
|
||||||
|
|
||||||
|
|||||||
@@ -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';
|
||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user