diff --git a/assets/css/scss/atoms/_checkbox.scss b/assets/css/scss/atoms/_checkbox.scss
index 75e8557a91..e340cf6e2e 100644
--- a/assets/css/scss/atoms/_checkbox.scss
+++ b/assets/css/scss/atoms/_checkbox.scss
@@ -2,7 +2,7 @@
@apply h-4 w-4;
.p-checkbox-box {
- @apply border border-solid border-gray-50 bg-white h-4 rounded w-4 transition-none;
+ @apply border border-solid border-gray-50 bg-white h-4 rounded w-4 transition-none invisible;
.p-checkbox-icon {
@apply text-caption font-semibold text-white;
diff --git a/assets/css/scss/atoms/_dropdown.scss b/assets/css/scss/atoms/_dropdown.scss
index 08dcca0093..19aa3b17ce 100644
--- a/assets/css/scss/atoms/_dropdown.scss
+++ b/assets/css/scss/atoms/_dropdown.scss
@@ -1,4 +1,4 @@
-.p-dropdown {
+.p-dropdown, .p-multiselect {
@apply border border-support-3 bg-white rounded-lg transition w-full duration-200
hover:border-primary hover:text-gray-90 hover:outline-0 hover:outline-none;
@@ -8,7 +8,7 @@
}
}
- .p-dropdown-label {
+ .p-dropdown-label, .p-multiselect-label {
@apply bg-transparent border-none
focus:outline-0 focus:outline-none;
@@ -29,7 +29,7 @@
}
}
-.p-dropdown-panel {
+.p-dropdown-panel, .p-autocomplete-panel, .p-multiselect-panel {
@apply bg-white rounded-lg text-gray-90 shadow-lg;
.p-dropdown-header {
@@ -88,4 +88,7 @@
}
}
}
+.p-multiselect-label-container {
+ @apply p-2;
+}
diff --git a/assets/vue/components/basecomponents/BaseAutocomplete.vue b/assets/vue/components/basecomponents/BaseAutocomplete.vue
index 4a2de10ea1..06bd4bb145 100644
--- a/assets/vue/components/basecomponents/BaseAutocomplete.vue
+++ b/assets/vue/components/basecomponents/BaseAutocomplete.vue
@@ -86,8 +86,12 @@ const baseModel = ref([])
const suggestions = ref([])
const onComplete = async (event) => {
- const members = await props.search(event.query)
-
- suggestions.value = members.length > 0 ? members : []
+ try {
+ const members = await props.search(event.query)
+ suggestions.value = members && members.length ? members : []
+ } catch (error) {
+ console.error('Error during onComplete:', error)
+ suggestions.value = []
+ }
}
diff --git a/assets/vue/components/basecomponents/BaseDropdown.vue b/assets/vue/components/basecomponents/BaseDropdown.vue
index 6c07108563..3a5a8a6c53 100644
--- a/assets/vue/components/basecomponents/BaseDropdown.vue
+++ b/assets/vue/components/basecomponents/BaseDropdown.vue
@@ -15,11 +15,12 @@
+ {{ helpText }}
diff --git a/assets/vue/components/basecomponents/BaseInputTags.vue b/assets/vue/components/basecomponents/BaseInputTags.vue
new file mode 100644
index 0000000000..56350d6279
--- /dev/null
+++ b/assets/vue/components/basecomponents/BaseInputTags.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
diff --git a/assets/vue/components/basecomponents/BaseInputText.vue b/assets/vue/components/basecomponents/BaseInputText.vue
index db18f6b747..b38d0870e7 100644
--- a/assets/vue/components/basecomponents/BaseInputText.vue
+++ b/assets/vue/components/basecomponents/BaseInputText.vue
@@ -7,22 +7,12 @@
:class="{ 'p-invalid': isInvalid }"
:aria-label="label"
type="text"
- @update:model-value="$emit('update:modelValue', $event)"
- />
-
+
-
-
-
+ {{ errorText }}
+ {{ helpText }}
@@ -47,14 +37,26 @@ const props = defineProps({
errorText: {
type: String,
required: false,
- default: null,
+ default: "",
},
isInvalid: {
type: Boolean,
required: false,
default: false,
},
+ required: {
+ type: Boolean,
+ default: false,
+ },
+ helpText: String,
+ formSubmitted: {
+ type: Boolean,
+ default: false
+ },
})
-defineEmits(["update:modelValue"])
+const emits = defineEmits(["update:modelValue"])
+const updateValue = (value) => {
+ emits("update:modelValue", value)
+}
diff --git a/assets/vue/components/basecomponents/BaseMultiSelect.vue b/assets/vue/components/basecomponents/BaseMultiSelect.vue
new file mode 100644
index 0000000000..1f4c21cdec
--- /dev/null
+++ b/assets/vue/components/basecomponents/BaseMultiSelect.vue
@@ -0,0 +1,67 @@
+
+
+
+
+
diff --git a/assets/vue/components/basecomponents/BaseToolbar.vue b/assets/vue/components/basecomponents/BaseToolbar.vue
index f2ed1f2d03..9c24587c95 100644
--- a/assets/vue/components/basecomponents/BaseToolbar.vue
+++ b/assets/vue/components/basecomponents/BaseToolbar.vue
@@ -1,26 +1,29 @@
-
-
+
+
+
+
+
diff --git a/assets/vue/components/course/Form.vue b/assets/vue/components/course/Form.vue
index c89202751d..93ec575b4e 100644
--- a/assets/vue/components/course/Form.vue
+++ b/assets/vue/components/course/Form.vue
@@ -1,174 +1,174 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
diff --git a/assets/vue/layouts/MyCourses.vue b/assets/vue/layouts/MyCourses.vue
index bc7b139a20..9c6cf332c6 100644
--- a/assets/vue/layouts/MyCourses.vue
+++ b/assets/vue/layouts/MyCourses.vue
@@ -6,6 +6,7 @@
:label="t('Course')"
class="p-button-secondary hidden md:inline-flex"
icon="pi pi-plus"
+ @click="redirectToCreateCourse"
/>
@@ -17,7 +18,13 @@ import Button from 'primevue/button';
import { useI18n } from 'vue-i18n';
import { storeToRefs } from "pinia"
import { useSecurityStore } from "../store/securityStore"
+import { useRouter } from "vue-router"
const { t } = useI18n();
const { isTeacher } = storeToRefs(useSecurityStore())
+const router = useRouter()
+
+const redirectToCreateCourse = () => {
+ router.push({ name: 'CourseCreate' })
+}
diff --git a/assets/vue/services/courseService.js b/assets/vue/services/courseService.js
index 7c5a5da404..0021ff868f 100644
--- a/assets/vue/services/courseService.js
+++ b/assets/vue/services/courseService.js
@@ -1,6 +1,7 @@
import { ENTRYPOINT } from "../config/entrypoint"
import axios from "axios"
+const API_URL = '/course';
const courseService = {
/**
* @param {number} courseId
@@ -71,7 +72,7 @@ const courseService = {
*/
checkLegal: async (courseId, sessionId = 0) => {
const { data } = await axios.get(
- `/course/${courseId}/checkLegal.json`,
+ `${API_URL}/${courseId}/checkLegal.json`,
{
params: {
sid: sessionId,
@@ -81,6 +82,41 @@ const courseService = {
return data
},
+
+ /**
+ * Creates a new course with the provided data.
+ * @param {Object} courseData - The data for the course to be created.
+ * @returns {Promise