Skip to content

Commit

Permalink
Merge branch 'dev' into permission-middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
reyniersbram committed May 22, 2024
2 parents 3a291c9 + 9ee3b67 commit ff7545e
Show file tree
Hide file tree
Showing 27 changed files with 1,097 additions and 152 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<template>
<v-row class="body">
<v-col cols="4">
<SubjectInstructorsCard
:instructors="instructors"
@remove-instructor="$emit('remove-instructor', $event)"
></SubjectInstructorsCard>
</v-col>
<v-col cols="8">
<UserSearchCard
:current-user="currentUser"
:instructors="instructors"
@add-instructor="$emit('add-instructor', $event)"
></UserSearchCard>
</v-col>
</v-row>
</template>

<script setup lang="ts">
import SubjectInstructorsCard from "@/components/subject/createSubjectView/body/SubjectInstructorsCard.vue";
import type User from "@/models/User";
import UserSearchCard from "@/components/subject/createSubjectView/body/UserSearchCard.vue";
defineProps<{
currentUser: User;
instructors: User[];
}>();
defineEmits<{
(e: "add-instructor", user: User): void;
(e: "remove-instructor", user: User): void;
}>();
</script>

<style scoped></style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<template>
<v-card variant="text" width="100%" class="title-card" height="100%">
<v-card-title class="card-title">
{{ $t("create_subject.subject_instructors") }}
</v-card-title>
<v-card-text>
<v-chip
v-for="instructor in instructors"
:key="instructor!.uid"
closable
variant="elevated"
:color="instructor!.is_teacher ? `primary` : `green`"
@click:close="$emit('remove-instructor', instructor)"
class="ma-1"
>
<v-icon
:icon="instructor!.is_teacher ? `mdi-account-tie-outline` : `mdi-school`"
start
></v-icon>
{{ instructor.given_name[0] }}. {{ instructor.surname }}
</v-chip>
</v-card-text>
</v-card>
</template>

<script setup lang="ts">
import type User from "@/models/User";
defineProps<{
instructors: User[];
}>();
defineEmits<{
(e: "remove-instructor", user: User): void;
}>();
</script>

<style scoped>
.title-card {
background-color: var(--color-secondary);
padding: 20px;
}
.card-title {
font-size: 24px;
text-transform: capitalize;
display: block;
line-height: 1.2;
font-weight: 500;
color: black;
word-wrap: break-word;
white-space: normal;
overflow: hidden;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<template>
<v-card variant="text" class="title-card" width="100%" height="50vh">
<v-card-title class="card-title">
{{ $t("create_subject.search_for_instructors") }}
</v-card-title>
<v-card-text>
<UserSearchList
:current-user="currentUser"
:instructors="instructors"
@add-instructor="$emit('add-instructor', $event)"
>
</UserSearchList>
</v-card-text>
</v-card>
</template>

<script setup lang="ts">
import UserSearchList from "@/components/subject/createSubjectView/body/UserSearchList.vue";
import type User from "@/models/User";
defineProps<{
currentUser: User;
instructors: User[];
}>();
defineEmits<{
(e: "add-instructor", user: User): void;
}>();
</script>

<style scoped>
.title-card {
background-color: var(--color-secondary);
padding: 20px;
}
.card-title {
font-size: 24px;
text-transform: capitalize;
display: block;
line-height: 1.2;
font-weight: 500;
color: black;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<template>
<v-text-field
:loading="searchLoading"
v-model="search"
:label="$t('default.search')"
:placeholder="$t('create_subject.search_for_instructors')"
prepend-inner-icon="mdi-magnify"
clearable
single-line
hide-details
variant="outlined"
@click:prepend-inner="onSearchIconClicked"
@keydown.enter="onSearchIconClicked"
></v-text-field>

<div class="scrollable-list">
<p v-if="shownUsers.length === 0">No results found</p>
<v-list v-else>
<v-list-item v-for="(user, index) in shownUsers" :key="index">
<v-row>
<v-col>
<v-list-item-title>
{{ user.given_name }} {{ user.surname }}
</v-list-item-title>
</v-col>
<v-col>
<v-btn
@click="$emit('add-instructor', user)"
color="primary"
:disabled="userIsInstructor(user)"
>
{{ $t("default.add") }}
</v-btn>
</v-col>
</v-row>
</v-list-item>
</v-list>
</div>
</template>

<script setup lang="ts">
import { useUsersQuery } from "@/queries/User";
import { computed, ref, toRefs } from "vue";
import type User from "@/models/User";
const props = defineProps<{
instructors: User[];
currentUser: User;
}>();
const { instructors, currentUser } = toRefs(props);
const { data: users } = useUsersQuery();
const search = ref("");
const searchLoading = ref(false);
const searchLoaded = ref(false);
const shownUsers = computed(() => {
if (!search.value) {
return [];
}
return [...(users.value || [])]
.sort((a: User, b: User) => {
return a.surname.localeCompare(b.surname);
})
.filter((user: User) => {
return (
user?.uid !== currentUser.value?.uid &&
`${user?.given_name} ${user.surname}`
.toLowerCase()
.includes(search.value.toLowerCase())
);
});
});
defineEmits<{
(e: "add-instructor", user: User): void;
}>();
const onSearchIconClicked = () => {
searchLoading.value = true;
setTimeout(() => {
searchLoaded.value = true;
searchLoading.value = false;
}, 1000);
};
const userIsInstructor = (user: User) => {
return instructors.value.some((instructor: User) => instructor?.uid === user?.uid);
};
</script>

<style scoped>
.scrollable-list {
overflow-y: auto;
max-height: 30vh;
scrollbar-width: none;
}
.scrollable-list::-webkit-scrollbar {
width: 0; /* For Chrome, Safari, and Opera */
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<template>
<v-card variant="text" class="title-card" width="100%" height="45vh">
<v-card-title class="title">
{{ $t("create_subject.new_subject") }}
</v-card-title>

<v-card-text>
<v-text-field
v-model="subjectName"
:rules="[rules.required, rules.length]"
:label="$t('create_subject.title')"
required
variant="outlined"
:placeholder="$t('create_subject.enter_title')"
clearable
hide-details="auto"
@keydown.enter.prevent
:error="isSubjectNameError"
class="form-elem"
></v-text-field>

<v-row>
<v-col>
<v-select
v-model="activeAcademicYear"
variant="outlined"
:items="academicYearItems"
:item-title="(item) => `20${item}-20${item + 1}`"
:item-value="(item) => item"
:label="$t('subject.academy_year')"
required
class="form-elem-academic"
></v-select>
</v-col>
<v-col>
<v-checkbox
:label="$t('create_subject.assign_self')"
v-model="checkbox"
color="primary"
class="checkbox"
></v-checkbox>
</v-col>
</v-row>
<v-text-field
v-model="subjectMail"
type="email"
variant="outlined"
:rules="[rules.email]"
:label="$t('create_subject.email')"
clearable
:placeholder="$t('create_subject.enter_email')"
:hint="$t('create_subject.email_hint')"
hide-details="auto"
@keydown.enter.prevent
:error="isSubjectMailError"
class="form-elem"
>
</v-text-field>
</v-card-text>
</v-card>
</template>

<script setup lang="ts">
import { ref, toRefs, watch } from "vue";
import useAcademicYear from "@/composables/useAcademicYear";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const props = defineProps<{
currentUserAsInstructor: boolean;
isSubjectNameError: boolean;
isSubjectMailError: boolean;
}>();
const { currentUserAsInstructor } = toRefs(props);
const checkbox = ref(currentUserAsInstructor.value);
watch(currentUserAsInstructor, (newValue) => {
checkbox.value = newValue;
});
const subjectName = ref("");
const subjectMail = ref("");
const activeAcademicYear = ref<number>(useAcademicYear());
const academicYearItems = [activeAcademicYear.value, activeAcademicYear.value + 1];
const rules = {
required: (value: string) => !!value || t("create_subject.field_required"),
length: (value: string) => value.length > 2 || t("create_subject.field_length"),
email: (value: string) =>
!value || /.+@.+\..+/.test(value) || t("create_subject.email_invalid"),
};
const emit = defineEmits<{
(e: "update:current-user-as-instructor", value: boolean): void;
(e: "update:subject-name", value: string): void;
(e: "update:active-academic-year", value: number): void;
(e: "update:subject-mail", value: string): void;
}>();
watch(subjectName, (newValue) => {
emit("update:subject-name", newValue);
});
watch(activeAcademicYear, (newValue) => {
emit("update:active-academic-year", newValue);
});
watch(checkbox, (newValue) => {
emit("update:current-user-as-instructor", newValue);
});
watch(subjectMail, (newValue) => {
emit("update:subject-mail", newValue);
});
</script>

<style scoped>
.title-card {
background-color: var(--color-secondary);
padding: 20px;
}
.form-elem {
margin-bottom: 2vh;
margin-top: -3vh;
}
.form-elem-academic {
max-width: 20vw;
}
.title {
font-size: 32px;
letter-spacing: -0.5px;
text-transform: capitalize;
font-weight: bold;
margin-bottom: 4vh;
font-family: "Poppins", sans-serif;
}
</style>
Loading

0 comments on commit ff7545e

Please sign in to comment.