This commit is contained in:
f4ilji
2025-01-30 00:31:40 +05:00
parent bad611eb84
commit 3385dc5807
60 changed files with 1811 additions and 825 deletions
+143 -162
View File
@@ -5,23 +5,34 @@ import { debounce } from "lodash";
import { Link } from "@inertiajs/vue3";
import MainPageNavBar from "@/Navbars/MainPageNavbar.vue";
import BaseIcon from "@/Components/BaseComponents/BaseIcon.vue";
import ClientScheduleFilter from "@/Components/BuilderUi/Schedules/ClientScheduleFilter.vue";
export default {
name: "Index",
data() {
return {
searchInput: this.searchRequest,
favoriteGroups: JSON.parse(localStorage.getItem('favoriteGroups')) || [],
searchInput: this.filters.search_filter.value,
favoriteGroups: JSON.parse(localStorage.getItem('favoriteGroups')),
showFavorites: false,
loading: false,
};
},
components: {BaseIcon, MainPageNavBar, ClientFooterDown, MainNavbar, Link},
props: [
'educationalGroups',
'mainSections',
'searchRequest',
'navigation',
],
components: {ClientScheduleFilter, BaseIcon, MainPageNavBar, ClientFooterDown, MainNavbar, Link},
props: {
navigation: {
type: Object
},
filters: {
type: Object
},
forms_education: {
type: Object
},
schedulesByFaculty: {
type: Object
}
},
methods: {
search: debounce(function () {
this.$inertia.reload({
@@ -34,7 +45,7 @@ export default {
});
}, 300),
toggleFavorite(group) {
const index = this.favoriteGroups.findIndex(g => g.id === group.id);
const index = this.favoriteGroups.findIndex(g => g === group);
if (index === -1) {
this.favoriteGroups.push(group);
} else {
@@ -43,18 +54,65 @@ export default {
localStorage.setItem('favoriteGroups', JSON.stringify(this.favoriteGroups));
},
isFavorite(group) {
return this.favoriteGroups.some(g => g.id === group.id);
return this.favoriteGroups.some(g => g === group);
},
toggleShowFavorites() {
this.showFavorites = !this.showFavorites;
},
},
computed: {
filteredGroups() {
if (this.showFavorites) {
return this.educationalGroups.data.filter(group => this.favoriteGroups.some(g => g.id === group.id));
this.loading = true; // Включаем состояние загрузки
if (this.filters.favorite_filter.value === null) {
this.filterFavorite(() => {
this.loading = false; // Выключаем состояние загрузки после завершения
});
} else {
this.clearFilterFavorite(() => {
this.loading = false; // Выключаем состояние загрузки после завершения
});
}
return this.educationalGroups.data;
},
filterFavorite: debounce(function (callback) {
let url = new URL(window.location.href);
// Создаем массив для хранения всех ключей, которые нужно удалить
const keysToDelete = [];
// Перебираем все параметры и добавляем ключи, начинающиеся с 'category', в массив
for (const [key] of url.searchParams) {
if (key.startsWith('favorite')) {
keysToDelete.push(key);
}
}
// Удаляем все ключи из массива
keysToDelete.forEach(key => url.searchParams.delete(key));
let newUrl = url.toString();
this.$inertia.visit(newUrl, {
method: 'get',
preserveState: true,
data: {
favorite: (this.favoriteGroups.length !== 0) ? this.favoriteGroups : "",
},
onFinish: callback, // Вызываем колбэк после завершения запроса
});
}, 500),
clearFilterFavorite(callback) {
let url = new URL(window.location.href);
// Создаем массив для хранения всех ключей, которые нужно удалить
const keysToDelete = [];
// Перебираем все параметры и добавляем ключи, начинающиеся с 'category', в массив
for (const [key] of url.searchParams) {
if (key.startsWith('favorite')) {
keysToDelete.push(key);
}
}
// Удаляем все ключи из массива
keysToDelete.forEach(key => url.searchParams.delete(key));
let newUrl = url.toString();
this.$inertia.visit(newUrl, {
method: 'get',
preserveState: true,
onFinish: callback, // Вызываем колбэк после завершения запроса
});
},
},
};
@@ -69,14 +127,13 @@ export default {
<article class="w-full min-w-0 mt-4 px-1 md:px-6">
<div class="relative overflow-hidden">
<div class="max-w-[85rem] mx-auto sm:px-6 lg:px-8 py-10 sm:pb-12 sm:py-5">
<div class="text-center">
<h1 class="text-2xl sm:text-4xl font-bold text-gray-800 dark:text-gray-200">
<div class="">
<h1 class="text-2xl sm:text-4xl font-bold text-gray-800 text-center">
Расписание занятий
</h1>
<div class="text-center">
<p class="mt-3 text-gray-600 dark:text-gray-400">
<div class="">
<p class="mt-3 text-gray-600 text-center">
Просто введите название группы
</p>
</div>
@@ -100,7 +157,7 @@ export default {
id="hs-search-article-1"
class="py-2.5 px-4 block w-full border-transparent rounded-lg disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-gray-100"
placeholder="Поиск"
:disabled="showFavorites"
:disabled="filters.favorite_filter.value !== null"
>
</div>
</div>
@@ -108,24 +165,20 @@ export default {
</form>
<div class="">
<div class="grid grid-cols-2 gap-3">
<button @click="toggleShowFavorites" type="button"
:class="showFavorites ? 'bg-primaryBlue text-white hover:bg-secondDarkBlue' : 'text-gray-700 hover:bg-gray-100'"
class="flex w-full py-2 px-4 items-center gap-x-2 text-xs font-medium rounded-lg border border-gray-200 focus:outline-none disabled:opacity-50 disabled:pointer-events-none">
<button
@click="toggleShowFavorites"
type="button"
:disabled="favoriteGroups.length === 0 || loading"
:class="
filters.favorite_filter.value !== null ? 'bg-primaryBlue text-white hover:bg-secondDarkBlue': 'text-gray-700 hover:bg-gray-100',
loading ? 'animate-pulse' : ''
"
class="flex w-full py-2 px-4 items-center gap-x-2 text-xs font-medium rounded-lg border border-gray-200 focus:outline-none disabled:opacity-50 disabled:pointer-events-none"
>
<BaseIcon name="heart" class="shrink-0 size-4"/>
<span>Избранные расписания</span>
</button>
<button type="button"
class="flex w-full py-2 px-4 items-center gap-x-2 text-xs font-medium rounded-lg border border-gray-200 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-primaryBlue focus:text-white disabled:opacity-50 disabled:pointer-events-none">
<svg class="shrink-0 size-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24"
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round">
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<line x1="19" x2="19" y1="8" y2="14"/>
<line x1="22" x2="16" y1="11" y2="11"/>
</svg>
<span>Follow</span>
<span>Избранное</span>
</button>
<ClientScheduleFilter :forms_educational="this.forms_education" :form-edu_filter="this.filters.form_education_filter" />
</div>
</div>
</div>
@@ -133,131 +186,59 @@ export default {
</div>
</div>
<div class="mx-auto max-w-2xl hs-accordion-group grid grid-cols-1 lg:grid-cols-2 gap-3">
<div v-if="!showFavorites">
<div class="mx-auto max-w-2xl hs-accordion-group grid gap-3">
<div class="space-y-4">
<transition-group name="fade">
<template v-for="educationalGroup in filteredGroups" :key="educationalGroup.id">
<div
class="hs-accordion hs-accordion-active:border-gray-200 bg-white border-b dark:hs-accordion-active:border-gray-700 dark:bg-gray-800 dark:border-transparent"
id="hs-active-bordered-heading-one">
<div class="flex">
<button @click="toggleFavorite(educationalGroup)">
<transition name="heart" mode="out-in">
<BaseIcon
v-if="isFavorite(educationalGroup)"
name="heart_filled"
class="shrink-0 size-4 text-red-500"
key="filled"
/>
<BaseIcon
v-else
name="heart"
class="shrink-0 size-4"
key="outline"
/>
</transition>
<template v-for="(faculty, title) in schedulesByFaculty">
<div class="">
<h2 class="text-center text-gray-800 font-medium">{{ title }}</h2>
<hr class="mt-2 mb-4">
<template v-for="educationalGroup in faculty" :key="educationalGroup.data.id">
<div class="hs-accordion hs-accordion-active:border-gray-200 bg-white border border-transparent rounded-xl" id="hs-active-bordered-heading-one">
<div class="flex py-4 px-5 gap-x-3">
<button @click="toggleFavorite(educationalGroup.data.id)">
<transition name="heart" mode="out-in">
<BaseIcon
v-if="isFavorite(educationalGroup.data.id)"
name="heart_filled"
class="shrink-0 size-4 text-red-500"
key="filled"
/>
<BaseIcon
v-else
name="heart"
class="shrink-0 size-4"
key="outline"
/>
</transition>
</button>
</button>
<button class="hs-accordion-toggle hs-accordion-active:text-blue-600 inline-flex justify-between items-center gap-x-3 w-full font-semibold text-start text-gray-800 hover:text-gray-500 disabled:opacity-50 disabled:pointer-events-none" aria-expanded="false" aria-controls="hs-basic-active-bordered-collapse-one">
<span class="flex items-center gap-x-2">{{ educationalGroup.data.title }}</span>
<svg class="hs-accordion-active:hidden block size-3.5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path>
</svg>
<svg class="hs-accordion-active:block hidden size-3.5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M5 12h14"></path>
</svg>
</button>
</div>
<button
class="hs-accordion-toggle hs-accordion-active:text-blue-600 inline-flex justify-between items-center gap-x-3 w-full font-semibold text-start text-gray-800 py-4 px-5 hover:text-gray-500 disabled:opacity-50 disabled:pointer-events-none dark:hs-accordion-active:text-blue-500 dark:text-gray-200 dark:hover:text-gray-400 dark:focus:outline-none dark:focus:text-gray-400"
aria-controls="hs-basic-active-bordered-collapse-one">
<div class="flex items-center gap-x-2"><span>{{ educationalGroup.title }}</span> <span
class="font-light text-sm uppercase text-gray-500">{{ educationalGroup.faculty }}</span></div>
<svg class="hs-accordion-active:hidden block w-3.5 h-3.5"
xmlns="http://www.w3.org/2000/svg"
width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M5 12h14"/>
<path d="M12 5v14"/>
</svg>
<svg class="hs-accordion-active:block hidden w-3.5 h-3.5"
xmlns="http://www.w3.org/2000/svg"
width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M5 12h14"/>
</svg>
</button>
</div>
<div id="hs-basic-active-bordered-collapse-one"
class="hs-accordion-content hidden w-full overflow-hidden transition-[height] duration-300"
aria-labelledby="hs-active-bordered-heading-one">
<div class="pb-4 px-5 grid gap-3 grid-cols-1">
<template v-for="schedule in educationalGroup.schedules" :key="schedule.id">
<template v-for="file in schedule.file">
<a :href="'storage/' + file.path" target="_blank"
class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-gray-200 bg-white text-gray-500 shadow-sm hover:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-800 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600">
{{ file.title }}
</a>
</template>
</template>
<div id="hs-basic-active-bordered-collapse-one" class="hs-accordion-content hidden w-full overflow-hidden transition-[height] duration-300" role="region" aria-labelledby="hs-active-bordered-heading-one">
<div class="pb-4 px-5 grid gap-3 grid-cols-1">
<template v-for="schedule in educationalGroup.data.schedules" :key="schedule.id">
<template v-for="file in schedule.file">
<a :href="'storage/' + file.path" target="_blank"
class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-gray-200 bg-white text-gray-500 shadow-sm hover:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-800 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600">
{{ file.title }}
</a>
</template>
</template>
</div>
</div>
</div>
</div>
</div>
</template>
</transition-group>
</div>
<div v-else>
<transition-group name="fade">
<template v-for="educationalGroup in favoriteGroups" :key="educationalGroup.id">
<div
class="hs-accordion hs-accordion-active:border-gray-200 bg-white border-b dark:hs-accordion-active:border-gray-700 dark:bg-gray-800 dark:border-transparent"
id="hs-active-bordered-heading-one">
<div class="flex">
<button @click="toggleFavorite(educationalGroup)">
<transition name="heart" mode="out-in">
<BaseIcon
v-if="isFavorite(educationalGroup)"
name="heart_filled"
class="shrink-0 size-4 text-red-500"
key="filled"
/>
<BaseIcon
v-else
name="heart"
class="shrink-0 size-4"
key="outline"
/>
</transition>
</button>
<button
class="hs-accordion-toggle hs-accordion-active:text-blue-600 inline-flex justify-between items-center gap-x-3 w-full font-semibold text-start text-gray-800 py-4 px-5 hover:text-gray-500 disabled:opacity-50 disabled:pointer-events-none dark:hs-accordion-active:text-blue-500 dark:text-gray-200 dark:hover:text-gray-400 dark:focus:outline-none dark:focus:text-gray-400"
aria-controls="hs-basic-active-bordered-collapse-one">
<div class="flex items-center gap-x-2"><span>{{ educationalGroup.title }}</span> <span
class="font-light text-sm uppercase text-gray-500">{{ educationalGroup.faculty }}</span></div>
<svg class="hs-accordion-active:hidden block w-3.5 h-3.5"
xmlns="http://www.w3.org/2000/svg"
width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M5 12h14"/>
<path d="M12 5v14"/>
</svg>
<svg class="hs-accordion-active:block hidden w-3.5 h-3.5"
xmlns="http://www.w3.org/2000/svg"
width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M5 12h14"/>
</svg>
</button>
</div>
<div id="hs-basic-active-bordered-collapse-one"
class="hs-accordion-content hidden w-full overflow-hidden transition-[height] duration-300"
aria-labelledby="hs-active-bordered-heading-one">
<div class="pb-4 px-5 grid gap-3 grid-cols-1">
<template v-for="schedule in educationalGroup.schedules" :key="schedule.id">
<template v-for="file in schedule.file">
<a :href="'storage/' + file.path" target="_blank"
class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-gray-200 bg-white text-gray-500 shadow-sm hover:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-800 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600">
{{ file.title }}
</a>
</template>
</template>
</div>
</div>
</template>
</div>
</template>
</transition-group>