Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create subjects page + Styling fixes subjects #227

Merged
merged 43 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
c4eb449
Merge remote-tracking branch 'origin/dev' into create_subject
mattiscauwel May 18, 2024
3e35231
added router to create SubjectsView.vue
mattiscauwel May 18, 2024
ac97ec7
added first form elements
mattiscauwel May 18, 2024
ce8f2ca
Merge branch 'subjects' into create_subject
mattiscauwel May 18, 2024
a563492
added submit button
mattiscauwel May 18, 2024
c9171ed
create subject via frontend works
mattiscauwel May 18, 2024
ce713aa
implemented search
mattiscauwel May 18, 2024
b62cde6
add users to instructors
mattiscauwel May 18, 2024
3cc9c31
assign and delete users from instructors
mattiscauwel May 18, 2024
2fac134
sort instructors
mattiscauwel May 18, 2024
5da86fb
begin styling create subject page
mattiscauwel May 18, 2024
e7d45c9
more styling
mattiscauwel May 19, 2024
90c9428
adding instsructors
mattiscauwel May 19, 2024
c25c746
remove instructors
mattiscauwel May 19, 2024
8344ed6
assign yourself button works
mattiscauwel May 19, 2024
cdfd01a
emit cleanup
mattiscauwel May 19, 2024
3affccc
emitted events fixed
mattiscauwel May 19, 2024
9cd62a8
add instructors to db
mattiscauwel May 19, 2024
6c45374
form validation
mattiscauwel May 19, 2024
4e30a39
implemented dialog
mattiscauwel May 19, 2024
9e9c729
added i18n
mattiscauwel May 19, 2024
b8d9398
Merge remote-tracking branch 'origin/dev' into create_subject
mattiscauwel May 19, 2024
f2ce8e1
i18n bug fixed
mattiscauwel May 19, 2024
c84a23c
styling details
mattiscauwel May 19, 2024
643819f
redirect after hitting confirm
mattiscauwel May 19, 2024
b23d72f
lint + format
mattiscauwel May 19, 2024
e27f86e
subjects overflow fix
mattiscauwel May 20, 2024
3e5815b
subject title card scrollable
mattiscauwel May 20, 2024
041a594
scrolling on overflow
mattiscauwel May 20, 2024
587d478
added v-chips and sorted instructors on subjectpage
mattiscauwel May 20, 2024
ae718d5
format + linter
mattiscauwel May 20, 2024
aa82fd6
style rollback subjects voor marieke
mattiscauwel May 20, 2024
850b2c0
linter format
mattiscauwel May 20, 2024
1d15183
deleted bg container on create page for better designing patch
mattiscauwel May 20, 2024
76d4d50
last changes on create subject
mattiscauwel May 20, 2024
5004b36
email and email rules
mattiscauwel May 21, 2024
63dcdff
added watcher
mattiscauwel May 21, 2024
3f8443e
added emits
mattiscauwel May 21, 2024
dcd6460
post mail fully functional
mattiscauwel May 21, 2024
349ffd6
removed on search loaded
mattiscauwel May 21, 2024
3768703
format linter
mattiscauwel May 21, 2024
a436136
update mutations for create subject
reyniersbram May 21, 2024
4b102c3
Merge remote-tracking branch 'origin/subjects' into subjects
mattiscauwel May 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
mattiscauwel marked this conversation as resolved.
Show resolved Hide resolved
></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
Loading