Skip to content

Commit

Permalink
Fixed and optimized several issues in the front end of the course set…
Browse files Browse the repository at this point in the history
…tings page (#1245)

1. Reset error state upon update of the "New Lecture" panel
2. Correct the style of the buttons in the create-lecture-form
3. On the edit-course page: When copying a course, ensure the correct display of yearW for winter semesters.
4. On edit-course page: Add a tooltip to explain that the current page is the setting page of the newly copied course, not the original one.
5. Add a tooltip to explain that the current page is the setting page of the newly copied course, not the original one.
6.  Search course on the create-course page: Hide the search result list if the input box is then emptied, and when the input box loses focus.
7. Reset yearW to empty string when year < 2000
8. Placeholder of "year" for a semester-selection
9. On create-course page, mark necessary field with red border if empty
10. Ensure the slug of new courses is url-safe
  • Loading branch information
YiranDuan721 authored Dec 25, 2023
1 parent 4ef1319 commit 20f0e4f
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 34 deletions.
22 changes: 13 additions & 9 deletions web/template/admin/admin_tabs/create-course.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@
{{template "header" .IndexData.TUMLiveContext}}
{{define "create-course"}}
<div class="text-1 container mx-auto"
x-data="{ tumonlineid: '', slug: '', title: '', year: '', yearW: '', semester: 'Wintersemester', numberAttendees: null, searchQuery: '', searchResults: [] }"
x-init="$watch('year',(value)=>{if(value<2000)return; yearW = (value%1000) + 1})">
x-data="{ tumonlineid: '', slug: '', title: '', year: '', yearW: '', semester: 'Wintersemester', numberAttendees: null, searchQuery: '', searchResults: [] , isSearchResultVisible: false}"
x-init="$watch('year',(value)=>{ yearW = (value<2000) ? '' : (value%1000) + 1 })">
<div class="min-w-screen flex items-center justify-center">
<div class="w-full lg:w-5/6 p-3 bg-gray-100 dark:bg-secondary rounded dark:border dark:border-gray-500 shadow">
<h2 class="mb-0">Find your course from TUMOnline</h2>
<form id="createCourseForm" aria-haspopup="listbox" class="grid gap-3 mt-3">
<div class="flex space-x-1">
<input class="w-full box-border rounded px-4 py-3 mt-3 focus:outline-none border-0 bg-gray-50 w-full dark:bg-gray-600 dark:text-white"
type="search" autocomplete="off" placeholder="Search" x-model="searchQuery"
<label for="search-course" class="hidden">Search Course</label>
<input class="w-full box-border rounded px-4 py-3 mt-3 focus:outline-none border-0 bg-gray-50 dark:bg-gray-600 dark:text-white"
id="search-course" type="search" autocomplete="off" placeholder="Search" x-model="searchQuery"
@change="fetch('/api/searchCourse?q='+searchQuery).then(r=>r.json()).then(r => searchResults=r)"
@keyup="fetch('/api/searchCourse?q='+searchQuery).then(r=>r.json()).then(r => searchResults=r)"/>
@keyup="fetch('/api/searchCourse?q='+searchQuery).then(r=>r.json()).then(r => searchResults=r)"
@focus="isSearchResultVisible = true"
@blur="setTimeout(() => isSearchResultVisible = false, 100)"/>
</div>
<div class="px-2" x-show="searchResults.length!==0">
<div class="px-2" x-show="isSearchResultVisible && searchQuery !== '' && searchResults.length!==0">
<ul role="listbox">
<template x-for="searchResult in searchResults">
<li role="option" aria-selected="false"
Expand All @@ -33,19 +36,20 @@
<h2>Manually enter Infos:</h2>
<div class="flex space-x-1">
<label for="name" class="hidden">Course Title</label>
<input class="w-4/5 tl-input !ml-0" id="name" name="name" type="text"
<input class="w-4/5 tl-input border !ml-0" id="name" name="name" type="text"
autocomplete="off"
placeholder="Einführung in die Informatik (IN0001)"
x-model="title"
required
:class="title === '' ? 'border-red-500 focus:border-red-500' : ''"/>
<label for="slug" class="hidden">Slug</label>
<input class="w-1/5 tl-input" id="slug" name="slug" type="text" x-ref="slug"
<input class="w-1/5 tl-input border" id="slug" name="slug" type="text" x-ref="slug"
autocomplete="off"
x-model="slug"
required
placeholder="eidi"
:class="slug === '' ? 'border-red-500 focus:border-red-500' : ''"/>
:class="slug === '' ? 'border-red-500 focus:border-red-500' : ''"
@input="slug = slug.replace(/[^A-Za-z0-9\-_.+()~]/g, '')"/>
</div>
{{template "semester-selection"}}
</form>
Expand Down
2 changes: 1 addition & 1 deletion web/template/admin/admin_tabs/edit-course.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<div x-cloak x-show="(new URL(document.location)).searchParams.get('copied')!==null"
class="p-4 text-sm text-green-700 bg-green-100 rounded-lg dark:bg-green-200 dark:text-green-800"
role="alert">
Course was copied successfully.
Course was copied successfully. Welcome to the settings page of your newly copied course.
</div>
<div x-cloak x-show="(new URL(document.location)).searchParams.get('created')!==null"
class="p-4 text-sm text-green-700 bg-green-100 rounded-lg dark:bg-green-200 dark:text-green-800"
Expand Down
12 changes: 11 additions & 1 deletion web/template/partial/course/manage/course_actions.gohtml
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
{{define "dangerzone"}}
{{- /*gotype: github.com/TUM-Dev/gocast/model.Course*/ -}}
<div class="form-container-body grid gap-3"
x-data="{ copying: false , year: '', yearW: '', semester: 'Wintersemester' }">
x-data="{ copying: false , year: '', yearW: '', semester: 'Wintersemester',
init() {
this.$watch('year', (newYear) => {
if (newYear.length === 4) {
const nextYear = parseInt(newYear) + 1;
this.yearW = ('' + nextYear).slice(-2);
} else {
this.yearW = '';
}
});
}}">
<div x-show="copying" class="grid gap-3">
{{template "semester-selection"}}
<button :disabled="year==''" class="btn" @click="admin.copyCourse('{{.Model.ID}}',year,yearW,semester)">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<button
x-data="{ itemCreateType: admin.LectureCreateType.livestream }"
@click.prevent="() => updateCreateType(itemCreateType)"
class="inline-flex items-center justify-between w-full p-5 text-gray-500 bg-white border border-gray-200 rounded-lg cursor-pointer dark:hover:text-gray-300 dark:border-gray-700 hover:text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:bg-gray-600 dark:hover:bg-gray-500"
:class="createType === itemCreateType ? 'dark:text-white dark:border-white border-blue-600 text-blue-600' : ''"
class="inline-flex items-center justify-between w-full p-5 bg-white border rounded-lg cursor-pointer dark:hover:text-gray-300 dark:border-gray-700 hover:text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:bg-gray-600 dark:hover:bg-gray-500"
:class="createType === itemCreateType ? 'dark:text-white dark:border-white border-blue-600 text-blue-600' : 'text-gray-500 border-gray-200'"
>
<div class="block text-left">
<div class="w-full text-lg font-semibold">Livestream</div>
Expand All @@ -17,8 +17,8 @@
<button
x-data="{ itemCreateType: admin.LectureCreateType.vodRecord }"
@click.prevent="() => updateCreateType(itemCreateType)"
class="inline-flex items-center justify-between w-full p-5 text-gray-500 bg-white border border-gray-200 rounded-lg cursor-pointer dark:hover:text-gray-300 dark:border-gray-700 hover:text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:bg-gray-600 dark:hover:bg-gray-500"
:class="createType === itemCreateType ? 'dark:text-white dark:border-white border-blue-600 text-blue-600' : ''"
class="inline-flex items-center justify-between w-full p-5 bg-white border rounded-lg cursor-pointer dark:hover:text-gray-300 dark:border-gray-700 hover:text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:bg-gray-600 dark:hover:bg-gray-500"
:class="createType === itemCreateType ? 'dark:text-white dark:border-white border-blue-600 text-blue-600' : 'text-gray-500 border-gray-200'"
>
<div class="block text-left">
<div class="w-full text-lg font-semibold">Record Lecture</div>
Expand All @@ -30,8 +30,8 @@
<button
x-data="{ itemCreateType: admin.LectureCreateType.vodUpload }"
@click.prevent="() => updateCreateType(itemCreateType)"
class="inline-flex items-center justify-between w-full p-5 text-gray-500 bg-white border border-gray-200 rounded-lg cursor-pointer dark:hover:text-gray-300 dark:border-gray-700 hover:text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:bg-gray-600 dark:hover:bg-gray-500"
:class="createType === itemCreateType ? 'dark:text-white dark:border-white border-blue-600 text-blue-600' : ''"
class="inline-flex items-center justify-between w-full p-5 bg-white border rounded-lg cursor-pointer dark:hover:text-gray-300 dark:border-gray-700 hover:text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:bg-gray-600 dark:hover:bg-gray-500"
:class="createType === itemCreateType ? 'dark:text-white dark:border-white border-blue-600 text-blue-600' : 'text-gray-500 border-gray-200'"
>
<div class="block text-left">
<div class="w-full text-lg font-semibold">Video Upload</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,15 @@
<span class="text-white rounded bg-danger px-4 py-2" >Something went wrong.</span>
</div>

<div x-show="!canContinue" class="flex justify-end px-6">
<span class="text-gray-500" style="white-space: pre-wrap; text-align: right;" x-text="cannotContinueReason"></span>
</div>

<div class="flex justify-end py-2 px-4">
<button x-show="!loading" :disabled="!canGoBack" class="mx-2 disabled:text-gray-300 dark:disabled:text-gray-500" @click.prevent="() => prev()">
Back
</button>
<button :disabled="loading || !canContinue" class="btn mx-2" @click.prevent="() => next()">
<button :disabled="loading || !canContinue" class="btn mx-2 disabled:text-gray-300 dark:disabled:text-gray-500" @click.prevent="() => next()">
<span x-show="!loading && !onLastSlide">Continue</span>
<span x-show="!loading && onLastSlide" x-text="formData.recurring && formData.recurringDates.filter(({enabled}) => enabled).length > 0
? `Create ${(formData.recurringDates.filter(({enabled}) => enabled).length + 1).toString()} Lectures`
Expand Down
12 changes: 9 additions & 3 deletions web/template/partial/course/manage/semester-selection.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,21 @@
<option value="Sommersemester">Sommersemester</option>
</select>
<label for="year" class="hidden">teachingTermYear</label>

<div class="flex">
<input id="year" x-model="year" name="year" class="w-32 tl-input"
:class="year === '' ? 'border-red-500 focus:border-red-500' : ''" placeholder="2022" type="number">
<input id="year" x-model="year" x-data="{initialYear: 2024}" name="year" class="w-32 tl-input border"
:class="year === '' ? 'border-red-500 focus:border-red-500' : ''"
:placeholder="year === '' ? initialYear : ''"
type="number"
@focus="if (year === '') year = initialYear">
<template x-if="semester === 'Wintersemester'">
<div class="flex">
<span class="mx-2 my-auto text-3">/</span>
<label for="yearW" class="hidden">teachingTermYearW</label>
<input id="yearW" x-model="yearW" name="yearW" class="w-16 tl-input"
:class="yearW === '' ? 'border-red-500 focus:border-red-500' : ''" type="text" readonly disabled>
:class="yearW === '' ? 'border-red-500 focus:border-red-500' : ''"
:placeholder="year === '' ? '25' : ''"
type="text" readonly disabled>
</div>
</template>
</div>
Expand Down
39 changes: 26 additions & 13 deletions web/ts/edit-course.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,10 +426,7 @@ export function saveLectureDescription(e: Event, cID: number, lID: number): Prom
e.preventDefault();
const input = (document.getElementById("lectureDescriptionInput" + lID) as HTMLInputElement).value;
return putData("/api/course/" + cID + "/updateDescription/" + lID, { name: input }).then((res) => {
if (res.status !== StatusCodes.OK) {
return false;
}
return true;
return res.status === StatusCodes.OK;
});
}

Expand All @@ -438,10 +435,7 @@ export function saveLectureName(e: Event, cID: number, lID: number): Promise<boo
e.preventDefault();
const input = (document.getElementById("lectureNameInput" + lID) as HTMLInputElement).value;
return postData("/api/course/" + cID + "/renameLecture/" + lID, { name: input }).then((res) => {
if (res.status !== StatusCodes.OK) {
return false;
}
return true;
return res.status === StatusCodes.OK;
});
}

Expand Down Expand Up @@ -745,6 +739,7 @@ export function createLectureForm(args: { s: [] }) {
error: false,
courseID: -1,
invalidReason: "",
cannotContinueReason: "",
init() {
this.onUpdate();
},
Expand All @@ -765,11 +760,7 @@ export function createLectureForm(args: { s: [] }) {
},
updateCreateType(newType: LectureCreateType) {
this.createType = newType;
if (newType === LectureCreateType.livestream) {
this.formData.vodup = false;
} else {
this.formData.vodup = true;
}
this.formData.vodup = newType !== LectureCreateType.livestream;
},
updateLiveAdHoc(adHoc: boolean) {
this.formData.adHoc = adHoc;
Expand Down Expand Up @@ -824,8 +815,11 @@ export function createLectureForm(args: { s: [] }) {

// This function sets flags depending on the current tab and current data
onUpdate() {
this.error = false;

if (this.currentTab === 0) {
this.canContinue = true;
this.cannotContinueReason = "";
this.canGoBack = false;
this.onLastSlide = false;
return;
Expand All @@ -838,10 +832,21 @@ export function createLectureForm(args: { s: [] }) {
// => we are not on the last tab
this.canGoBack = true;
this.canContinue = this.formData.start.length > 0;
this.cannotContinueReason = "";
if (this.formData.start.length <= 0) {
this.cannotContinueReason += "The start time for the lecture has not been set yet!\n";
}
} else {
this.onLastSlide = true;
this.canGoBack = true;
this.canContinue = this.formData.start.length > 0 && this.formData.end.length > 0;
this.cannotContinueReason = "";
if (this.formData.start.length <= 0) {
this.cannotContinueReason += "The start time for the lecture has not been set yet!\n";
}
if (this.formData.end.length <= 0) {
this.cannotContinueReason += "The end time for the lecture has not been set yet!\n";
}
}
return;
}
Expand All @@ -850,6 +855,14 @@ export function createLectureForm(args: { s: [] }) {
this.canContinue =
(this.getMediaFiles().length > 0 && this.formData.vodup) ||
(this.formData.adHoc && this.formData.end != "");
this.cannotContinueReason = "";
if (this.formData.vodup && this.getMediaFiles().length <= 0) {
this.cannotContinueReason += "No media files!\n";
}
if (this.formData.adHoc && this.formData.end == "") {
this.cannotContinueReason += "The end time for the lecture has not been set yet!\n";
}

this.canGoBack = true;
this.onLastSlide = true;
return;
Expand Down

0 comments on commit 20f0e4f

Please sign in to comment.