Skip to content
This repository was archived by the owner on Jul 27, 2024. It is now read-only.

Commit 6753092

Browse files
committed
Implement loading of course plans via FE
1 parent b31d1f2 commit 6753092

File tree

6 files changed

+231
-20
lines changed

6 files changed

+231
-20
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<template>
2+
<div class="box" dir="rtl">
3+
<h1 class="title">טעינת תכנית לימודים</h1>
4+
5+
6+
<div v-if="course_plans">
7+
<loadable-course-plan :plan="plan" v-for="plan in course_plans" :key="plan.id"
8+
@deletedPlan="handleDeletedPlan" @loadedPlan="handleLoadedPlan"/>
9+
10+
<div v-if="course_plans.length === 0">
11+
אין תכניות שמורות
12+
</div>
13+
</div>
14+
15+
<div v-if="isValidating">
16+
טוען ...
17+
<progress class="progress is-small is-primary" max="100">15%</progress>
18+
</div>
19+
20+
<div class="control">
21+
<button class="button is-link is-light" @click="$emit('close')">
22+
ביטול
23+
</button>
24+
</div>
25+
</div>
26+
</template>
27+
28+
<script>
29+
import { inject } from 'vue'
30+
import LoadableCoursePlan from "@/components/LoadableCoursePlan.vue"
31+
import useSWRV from 'swrv'
32+
33+
34+
export default {
35+
components: { LoadableCoursePlan },
36+
emits: [ "close"],
37+
setup(_props, { emit}) {
38+
console.log("LoadModal setup()")
39+
const http = inject("http")
40+
const fetcher = key => http.get(key).then(res => res.data.course_plans)
41+
const { data: course_plans, mutate, isValidating, error } = useSWRV("/student/me/", fetcher)
42+
43+
// used to hide deleted courses from the UI until the data is revalidated
44+
const deletedIds = new Set()
45+
46+
const handleDeletedPlan = async (deletedPlan) => {
47+
deletedIds.add(deletedPlan.id)
48+
await mutate()
49+
deletedIds.delete(deletedPlan.id)
50+
}
51+
52+
const handleLoadedPlan = () => {
53+
emit('close')
54+
}
55+
56+
return {
57+
course_plans, handleDeletedPlan, isValidating, error, handleLoadedPlan
58+
}
59+
}
60+
}
61+
</script>
62+
63+
<style>
64+
65+
</style>
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<template>
2+
<div class="card content">
3+
<header class="card-header">
4+
<p class="card-header-title">{{ plan.name }}</p>
5+
</header>
6+
7+
<div class="card-content">
8+
<div v-if="!plan.track">לא מוגדר מסלול</div>
9+
<div v-if="plan.track">מסלול: {{ plan.track.name }}</div>
10+
11+
<div class="level">
12+
<div class="level-left">
13+
שינוי אחרון:
14+
{{ new Date(plan.modified_at).toLocaleString() }}
15+
</div>
16+
<div class="level-right">
17+
נוצר ב:
18+
{{ new Date(plan.created_at).toLocaleString() }}
19+
</div>
20+
</div>
21+
22+
<div class="field is-grouped">
23+
<p class="control">
24+
<button
25+
class="button is-link"
26+
:class="{ 'is-loading': loading }"
27+
:disabled="deleting || loading"
28+
@click="onLoadPlan"
29+
>
30+
טעינה
31+
</button>
32+
</p>
33+
<p class="control">
34+
<button
35+
class="button is-danger"
36+
:class="{ 'is-loading': deleting }"
37+
:disabled="deleting || loading"
38+
@click="onDeleteClick"
39+
>
40+
מחיקה
41+
</button>
42+
</p>
43+
</div>
44+
</div>
45+
</div>
46+
</template>
47+
48+
<script>
49+
import { ref } from "vue";
50+
import { deletePlan, loadPlan } from "@/course-store.js";
51+
export default {
52+
props: {
53+
plan: Object,
54+
},
55+
emits: ["deletedPlan", "loadedPlan"],
56+
setup(props, { emit }) {
57+
const deleting = ref(false);
58+
const loading = ref(false);
59+
const onDeleteClick = async () => {
60+
deleting.value = true;
61+
try {
62+
await deletePlan(props.plan);
63+
emit("deletedPlan", props.plan);
64+
} finally {
65+
deleting.value = false;
66+
}
67+
};
68+
69+
const onLoadPlan = async () => {
70+
loading.value = true
71+
try {
72+
const fullPlan = await loadPlan(props.plan.id)
73+
emit("loadedPlan", fullPlan);
74+
} finally {
75+
loading.value = false;
76+
}
77+
};
78+
79+
return {
80+
onDeleteClick,
81+
deleting,
82+
onLoadPlan,
83+
loading
84+
};
85+
},
86+
};
87+
</script>
88+
89+
<style>
90+
</style>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<template>
2+
<div class="modal" :class="{ 'is-active': active }">
3+
<div class="modal-background" @click="$emit('close')"></div>
4+
<div class="modal-content">
5+
<slot v-if="active"/>
6+
</div>
7+
<button
8+
class="modal-close is-large"
9+
aria-label="close"
10+
@click="$emit('close')"
11+
></button>
12+
</div>
13+
</template>
14+
15+
<script>
16+
export default {
17+
props: {
18+
active: Boolean,
19+
},
20+
emits: ["close"],
21+
};
22+
</script>
23+
24+
<style>
25+
</style>

Closure_Front_End/src/components/SaveAsModal.vue

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<div class="field">
1717
<div class="control">
1818
<label class="checkbox">
19-
<input type="checkbox" v-model="publicize" />
19+
<input type="checkbox" v-model="publicize" :disabled="saving"/>
2020
ציבורי
2121
</label>
2222
</div>
@@ -52,13 +52,14 @@ export default {
5252
name: "",
5353
publicize: false,
5454
saving: false,
55+
savedPlan: null
5556
});
5657
5758
const onSubmit = async () => {
5859
state.saving = true;
5960
try {
60-
await saveAs({ name: state.name, publicize: state.publicize });
61-
emit("close");
61+
state.savedPlan = await saveAs({ name: state.name, publicize: state.publicize });
62+
// emit("close");
6263
} finally {
6364
state.saving = false;
6465
}

Closure_Front_End/src/components/SaveMenu.vue

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<a class="navbar-link"> קובץ </a>
44

55
<div class="navbar-dropdown">
6-
<a class="navbar-item"> טעינה </a>
6+
<a class="navbar-item" @click="openLoadMenu"> טעינה </a>
77
<a v-if="!saving" class="navbar-item" :class="{'is-disabled': !canSave}" @click="onSave"> שמירה </a>
88
<div class="navbar-item" v-if="saving">
99
<button class="navbar-item button is-loading" v-if="saving" disabled>
@@ -17,38 +17,38 @@
1717
<a class="navbar-item"> שיתוף </a>
1818
</div>
1919
</div>
20-
<div class="modal" :class="{ 'is-active': showSaveAsMenu }">
21-
<div class="modal-background" @click="closeSaveAsMenu"></div>
22-
<div class="modal-content">
20+
21+
22+
<modal :active="showingSaveAsMenu" @close="closeSaveAsMenu">
2323
<save-as-modal @close="closeSaveAsMenu" />
24-
</div>
25-
<button
26-
class="modal-close is-large"
27-
aria-label="close"
28-
@click="closeSaveAsMenu"
29-
></button>
30-
</div>
24+
</modal>
25+
26+
<modal :active="showingLoadMenu" @close="closeLoadMenu">
27+
<load-modal @close="closeLoadMenu" />
28+
</modal>
3129
</template>
3230

3331
<script>
3432
import { computed, ref } from "vue";
33+
import Modal from "@/components/Modal.vue";
3534
import SaveAsModal from "@/components/SaveAsModal.vue";
35+
import LoadModal from "@/components/LoadModal.vue";
3636
import { currentCourseplan, isDirty, save } from "@/course-store.js";
3737
export default {
38-
components: { SaveAsModal },
38+
components: { SaveAsModal, LoadModal, Modal },
3939
setup() {
4040
const canSave = isDirty;
4141
const canSaveAs = computed(() => currentCourseplan.value !== null);
42-
const showSaveAsMenu = ref(false);
42+
const showingSaveAsMenu = ref(false);
4343
4444
const displaySaveAs = () => {
45-
showSaveAsMenu.value = true;
45+
showingSaveAsMenu.value = true;
4646
};
47-
const closeSaveAsMenu = () => (showSaveAsMenu.value = false);
47+
const closeSaveAsMenu = () => (showingSaveAsMenu.value = false);
4848
4949
const saving = ref(false);
5050
const onSave = async () => {
51-
if (currentCourseplan == null) {
51+
if (currentCourseplan.value === null) {
5252
displaySaveAs();
5353
} else {
5454
saving.value = true;
@@ -60,14 +60,19 @@ export default {
6060
}
6161
};
6262
63+
const showingLoadMenu = ref(false)
64+
const openLoadMenu = () => showingLoadMenu.value = true;
65+
const closeLoadMenu = () => (showingLoadMenu.value = false);
66+
6367
return {
6468
canSave,
6569
canSaveAs,
66-
showSaveAsMenu,
70+
showingSaveAsMenu,
6771
onSave,
6872
displaySaveAs,
6973
closeSaveAsMenu,
7074
saving,
75+
showingLoadMenu, openLoadMenu, closeLoadMenu
7176
};
7277
},
7378
};

Closure_Front_End/src/course-store.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,31 @@ const onSavedSuccessfully = (newPlan) => {
5858
return newPlan;
5959
};
6060

61+
export const deletePlan = async (plan) => {
62+
const res = await http.delete(`/course_plans/${plan.id}`)
63+
console.log("deleted plan", plan, "result:", res)
64+
if (plan.id === state.courseplan?.id) {
65+
console.log("deleting own plan")
66+
state.courseplan = null
67+
state.dirty = true
68+
}
69+
}
70+
71+
export const loadPlan = async (planId) => {
72+
const plan = await http.get(`/course_plans/${planId}`).data
73+
console.log("loaded plan", plan)
74+
state.courseplan = plan
75+
state.track = plan.track ?? null
76+
const loadedCourses = plan.takes.map(take => ({
77+
...take.course, take: {
78+
semester: take.semester,
79+
year: take.year_in_studies
80+
}
81+
}))
82+
addCourses(loadedCourses, true)
83+
state.dirty = false
84+
}
85+
6186
watch(state, (newState) => {
6287
localStorage.setItem(LS_PATH, JSON.stringify(newState));
6388
});

0 commit comments

Comments
 (0)