From be8d23c319e907aecc9e603294553b7e7739903e Mon Sep 17 00:00:00 2001 From: Estrella Pan Date: Sat, 11 Jul 2026 12:36:50 +0200 Subject: [PATCH] fix(webui): hide archived anime from calendar --- webui/src/pages/index/calendar.test.ts | 104 +++++++++++++++++++++++++ webui/src/pages/index/calendar.vue | 7 +- 2 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 webui/src/pages/index/calendar.test.ts diff --git a/webui/src/pages/index/calendar.test.ts b/webui/src/pages/index/calendar.test.ts new file mode 100644 index 00000000..7d356b42 --- /dev/null +++ b/webui/src/pages/index/calendar.test.ts @@ -0,0 +1,104 @@ +import { mount } from '@vue/test-utils'; +import { createPinia, setActivePinia } from 'pinia'; +import { defineComponent } from 'vue'; +import type { Component } from 'vue'; +import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { useBangumiStore } from '@/store/bangumi'; +import { mockBangumiRule } from '@/test/mocks/api'; + +vi.mock('@/utils/axios', () => ({ + axios: { + get: vi.fn(), + post: vi.fn(), + patch: vi.fn(), + delete: vi.fn(), + put: vi.fn(), + }, +})); + +vi.mock('@/hooks/useBreakpointQuery', async () => { + const { ref } = await vi.importActual('vue'); + return { + useBreakpointQuery: () => ({ isMobile: ref(false) }), + }; +}); + +vi.mock('@/hooks/useMyI18n', () => ({ + useMyI18n: () => ({ + t: (key: string) => key, + returnUserLangMsg: () => '', + }), +})); + +vi.mock('@/hooks/useMessage', () => ({ + useMessage: () => ({ success: vi.fn() }), +})); + +const CalendarBoardStub = defineComponent({ + name: 'CalendarBoard', + props: { + groupedByDay: { + type: Object, + required: true, + }, + }, + template: '
', +}); + +describe('Calendar page', () => { + let CalendarPage: Component; + + beforeAll(async () => { + vi.stubGlobal('definePage', vi.fn()); + CalendarPage = (await import('./calendar.vue')).default; + }); + + beforeEach(() => { + setActivePinia(createPinia()); + }); + + function mountCalendar() { + return mount(CalendarPage, { + global: { + stubs: { + 'ab-icon-button': true, + 'calendar-board': CalendarBoardStub, + 'calendar-mobile-list': true, + 'calendar-rule-list-popup': true, + }, + }, + }); + } + + it('excludes archived rules from weekday groups', () => { + const store = useBangumiStore(); + store.bangumi = [ + { ...mockBangumiRule, id: 1, air_weekday: 0, archived: false }, + { ...mockBangumiRule, id: 2, air_weekday: 0, archived: true }, + ]; + + const wrapper = mountCalendar(); + const groupedByDay = wrapper + .getComponent(CalendarBoardStub) + .props('groupedByDay') as Record< + string, + Array<{ rules: Array<{ id: number }> }> + >; + + expect( + groupedByDay.mon.flatMap((group) => group.rules.map((rule) => rule.id)) + ).toEqual([1]); + }); + + it('shows the empty state when every rule is archived', () => { + const store = useBangumiStore(); + store.bangumi = [ + { ...mockBangumiRule, id: 1, air_weekday: 0, archived: true }, + ]; + + const wrapper = mountCalendar(); + + expect(wrapper.find('[data-testid="calendar-board"]').exists()).toBe(false); + expect(wrapper.find('.empty-guide').exists()).toBe(true); + }); +}); diff --git a/webui/src/pages/index/calendar.vue b/webui/src/pages/index/calendar.vue index c197976c..6b975807 100644 --- a/webui/src/pages/index/calendar.vue +++ b/webui/src/pages/index/calendar.vue @@ -7,7 +7,7 @@ definePage({ name: 'Calendar', }); -const { bangumi } = storeToRefs(useBangumiStore()); +const { activeBangumi } = storeToRefs(useBangumiStore()); const { getAll, openEditPopup } = useBangumiStore(); const { isMobile } = useBreakpointQuery(); const { t } = useMyI18n(); @@ -71,8 +71,7 @@ const groupedBangumiByDay = computed(() => { DAY_KEYS.forEach((key) => (itemsByDay[key] = [])); itemsByDay.unknown = []; - bangumi.value?.forEach((item) => { - if (item.deleted) return; + activeBangumi.value.forEach((item) => { const weekday = item.air_weekday; if (weekday != null && weekday >= 0 && weekday <= 6) { itemsByDay[DAY_KEYS[weekday]].push(item); @@ -90,7 +89,7 @@ const groupedBangumiByDay = computed(() => { }); const hasBangumi = computed(() => { - return bangumi.value && bangumi.value.some((b) => !b.deleted); + return activeBangumi.value.length > 0; }); function getDayLabel(key: string): string {