Skip to content

Commit 8c2413c

Browse files
authored
feat(filters): Add season filtering on Sales/Presences (#135)
2 parents 6f7cc6b + 9cd2e20 commit 8c2413c

File tree

10 files changed

+144
-77
lines changed

10 files changed

+144
-77
lines changed

app/components/Email/EmailReceiverSelection.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,15 @@
138138
}
139139
140140
if (onlyCurrentSeason.value) {
141-
urlParams.append('currentSeason[memberSeasons.season]', 'true')
141+
urlParams.append('current-season[memberSeasons.season]', 'true')
142142
}
143143
144144
if (onlyPreviousSeason.value) {
145-
urlParams.append('previousSeason[memberSeasons.season]', 'true')
145+
urlParams.append('previous-season[memberSeasons.season]', 'true')
146146
}
147147
148148
if (onlySeasonNotRenewed.value) {
149-
urlParams.append('seasonNotRenewed[memberSeasons.season]', 'true')
149+
urlParams.append('season-not-renewed[memberSeasons.season]', 'true')
150150
}
151151
152152
if (onlyWithLicence.value) {

app/components/ExternalPresence/ExternalPresenceList.vue

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,19 @@
6767
}
6868
6969
if (selectedRange.value) {
70-
const formattedStartDate = formatDateInput(selectedRange.value.start.toString())
71-
const formattedEndDate = formatDateInput(selectedRange.value.end.toString())
72-
if (formattedStartDate) {
73-
urlParams.append(`date[after]`, formattedStartDate);
74-
75-
if (formattedEndDate) {
76-
urlParams.append(`date[before]`, formattedEndDate);
77-
} else {
78-
urlParams.append(`date[before]`, formattedStartDate);
70+
if (typeof selectedRange.value.value === 'string') {
71+
urlParams.append(`${selectedRange.value.value}[date]`, 'true');
72+
} else {
73+
const formattedStartDate = formatDateInput(selectedRange.value.start.toString())
74+
const formattedEndDate = formatDateInput(selectedRange.value.end.toString())
75+
if (formattedStartDate) {
76+
urlParams.append(`date[after]`, formattedStartDate);
77+
78+
if (formattedEndDate) {
79+
urlParams.append(`date[before]`, formattedEndDate);
80+
} else {
81+
urlParams.append(`date[before]`, formattedStartDate);
82+
}
7983
}
8084
}
8185
}
@@ -131,15 +135,19 @@
131135
urlParams.append(`order[${sort.value.column}]`, sort.value.direction);
132136
133137
if (selectedRange.value) {
134-
const formattedStartDate = formatDateInput(selectedRange.value.start.toString())
135-
const formattedEndDate = formatDateInput(selectedRange.value.end.toString())
136-
if (formattedStartDate) {
137-
urlParams.append(`date[after]`, formattedStartDate);
138-
139-
if (formattedEndDate) {
140-
urlParams.append(`date[before]`, formattedEndDate);
141-
} else {
142-
urlParams.append(`date[before]`, formattedStartDate);
138+
if (typeof selectedRange.value === 'string') {
139+
urlParams.append(`${selectedRange.value.value}[date]`, 'true');
140+
} else {
141+
const formattedStartDate = formatDateInput(selectedRange.value.start.toString())
142+
const formattedEndDate = formatDateInput(selectedRange.value.end.toString())
143+
if (formattedStartDate) {
144+
urlParams.append(`date[after]`, formattedStartDate);
145+
146+
if (formattedEndDate) {
147+
urlParams.append(`date[before]`, formattedEndDate);
148+
} else {
149+
urlParams.append(`date[before]`, formattedStartDate);
150+
}
143151
}
144152
}
145153
} else {

app/components/Generic/GenericDateRangePicker.vue

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,23 @@
22
import { DatePicker as VCalendarDatePicker } from 'v-calendar'
33
import 'v-calendar/style.css'
44
import dayjs from "dayjs";
5-
import type {DateRange} from "~/types/date";
5+
import type {DateRange, DateRangeFilter} from "~/types/date";
66
7-
const date = defineModel<DateRange|undefined>({default: undefined})
7+
interface Range {
8+
label: string,
9+
duration: { type: string, value: string|number }
10+
}
11+
12+
const date = defineModel<DateRange|DateRangeFilter|undefined>({default: undefined})
13+
14+
const emit = defineEmits<{ rangeUpdated: [DateRange | DateRangeFilter | undefined] }>()
815
9-
const emit = defineEmits<{ rangeUpdated: [DateRange | undefined] }>()
16+
const props = defineProps({
17+
seasonSelectors: {
18+
type: Boolean,
19+
default: true
20+
}
21+
});
1022
1123
const columns = computed(() => {
1224
return isMobile().value ? 1 : 2
@@ -37,16 +49,35 @@ const ranges = [
3749
{ label: '30 derniers jours', duration: { type: 'day', value: 30 } },
3850
{ label: '3 derniers mois', duration: { type: 'month', value: 3 } },
3951
{ label: '6 derniers mois', duration: { type: 'month', value: 6 } },
40-
{ label: 'Dernière année', duration: { type: 'year', value: 1 } }
41-
]
52+
] as Range[]
4253
43-
function isRangeSelected (duration: { type: string, value: number }) {
54+
if (props.seasonSelectors) {
55+
ranges.push({ label: 'Saison actuelle', duration: { type: 'filter', value: 'current-season' } })
56+
ranges.push({ label: 'Saison précédente', duration: { type: 'filter', value: 'previous-season' } })
57+
58+
} else {
59+
ranges.push({ label: 'Dernière année', duration: { type: 'year', value: 1 } })
60+
}
61+
62+
function isRangeSelected(range: Range) {
4463
if (!date.value) return false
45-
return dayjs(date.value.start).isSame(dayjs().subtract(duration.value, duration.type), 'day') && dayjs().isSame(date.value.end, 'day')
64+
65+
const isFilter = typeof range.duration.value === 'string';
66+
if (isFilter) {
67+
return typeof date.value === 'object' && 'value' in date.value && date.value.value === range.duration.value;
68+
}
69+
70+
return dayjs(date.value.start).isSame(dayjs().subtract(range.duration.value, range.duration.type), 'day') && dayjs().isSame(date.value.end, 'day')
4671
}
4772
48-
function selectRange (duration: { type: string, value: number }) {
49-
date.value = { start: dayjs().subtract(duration.value, duration.type).toDate(), end: new Date() }
73+
function selectRange(range: Range) {
74+
const isFilter = typeof range.duration.value === 'string';
75+
if (isFilter) {
76+
date.value = { label: range.label, value: range.duration.value} as DateRangeFilter;
77+
return;
78+
}
79+
80+
date.value = { start: dayjs().subtract(range.duration.value, range.duration.type).toDate(), end: new Date() }
5081
}
5182
</script>
5283

@@ -60,9 +91,9 @@ function selectRange (duration: { type: string, value: number }) {
6091
color="neutral"
6192
variant="ghost"
6293
class="rounded-none px-6"
63-
:class="[isRangeSelected(range.duration) ? 'bg-gray-100 dark:bg-gray-800' : 'hover:bg-gray-50 dark:hover:bg-gray-800/50']"
94+
:class="[isRangeSelected(range) ? 'bg-gray-100 dark:bg-gray-800' : 'hover:bg-gray-50 dark:hover:bg-gray-800/50']"
6495
truncate
65-
@click="selectRange(range.duration)"
96+
@click="selectRange(range)"
6697
/>
6798
</div>
6899
<VCalendarDatePicker v-model.range="date" @update:model-value="emit('rangeUpdated', date)" :columns="columns" v-bind="{ ...attrs, ...$attrs }" />

app/components/Member/MemberList.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,15 @@ function getUrlParams(): URLSearchParams {
8484
}
8585
8686
if (onlyCurrentSeason.value) {
87-
urlParams.append('currentSeason[memberSeasons.season]', 'true');
87+
urlParams.append('current-season[memberSeasons.season]', 'true');
8888
}
8989
9090
if (onlyPreviousSeason.value) {
91-
urlParams.append('previousSeason[memberSeasons.season]', 'true');
91+
urlParams.append('previous-season[memberSeasons.season]', 'true');
9292
}
9393
9494
if (onlySeasonNotRenewed.value) {
95-
urlParams.append('seasonNotRenewed[memberSeasons.season]', 'true');
95+
urlParams.append('season-not-renewed[memberSeasons.season]', 'true');
9696
}
9797
9898
if (onlyWithLicence.value) {

app/components/PresentMember/PresentMemberList.vue

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,19 @@
6565
}
6666
6767
if (selectedRange.value) {
68-
const formattedStartDate = formatDateInput(selectedRange.value.start.toString())
69-
const formattedEndDate = formatDateInput(selectedRange.value.end.toString())
70-
if (formattedStartDate) {
71-
urlParams.append(`date[after]`, formattedStartDate);
72-
73-
if (formattedEndDate) {
74-
urlParams.append(`date[before]`, formattedEndDate);
75-
} else {
76-
urlParams.append(`date[before]`, formattedStartDate);
68+
if (typeof selectedRange.value.value === 'string') {
69+
urlParams.append(`${selectedRange.value.value}[date]`, 'true');
70+
} else {
71+
const formattedStartDate = formatDateInput(selectedRange.value.start.toString())
72+
const formattedEndDate = formatDateInput(selectedRange.value.end.toString())
73+
if (formattedStartDate) {
74+
urlParams.append(`date[after]`, formattedStartDate);
75+
76+
if (formattedEndDate) {
77+
urlParams.append(`date[before]`, formattedEndDate);
78+
} else {
79+
urlParams.append(`date[before]`, formattedStartDate);
80+
}
7781
}
7882
}
7983
}
@@ -128,15 +132,19 @@
128132
urlParams.append(`order[${sort.value.column}]`, sort.value.direction);
129133
130134
if (selectedRange.value) {
131-
const formattedStartDate = formatDateInput(selectedRange.value.start.toString())
132-
const formattedEndDate = formatDateInput(selectedRange.value.end.toString())
133-
if (formattedStartDate) {
134-
urlParams.append(`date[after]`, formattedStartDate);
135-
136-
if (formattedEndDate) {
137-
urlParams.append(`date[before]`, formattedEndDate);
138-
} else {
139-
urlParams.append(`date[before]`, formattedStartDate);
135+
if (typeof selectedRange.value.value === 'string') {
136+
urlParams.append(`${selectedRange.value.value}[date]`, 'true');
137+
} else {
138+
const formattedStartDate = formatDateInput(selectedRange.value.start.toString())
139+
const formattedEndDate = formatDateInput(selectedRange.value.end.toString())
140+
if (formattedStartDate) {
141+
urlParams.append(`date[after]`, formattedStartDate);
142+
143+
if (formattedEndDate) {
144+
urlParams.append(`date[before]`, formattedEndDate);
145+
} else {
146+
urlParams.append(`date[before]`, formattedStartDate);
147+
}
140148
}
141149
}
142150
} else {

app/pages/admin/thrombinoscope.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
4242
urlParams.append(`order[${sort.value.column}]`, sort.value.direction);
4343
urlParams.append(`order[firstname]`, 'asc');
44-
urlParams.append('currentSeason[memberSeasons.season]', 'true');
44+
urlParams.append('current-season[memberSeasons.season]', 'true');
4545
4646
memberQuery.getAll(urlParams).then(async value => {
4747
if (value.items) {

app/stores/usePresenceStore.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import type {ExternalPresence} from "~/types/api/item/clubDependent/plugin/prese
22
import ExternalPresenceQuery from "~/composables/api/query/clubDependent/plugin/presence/ExternalPresenceQuery";
33
import dayjs from "dayjs";
44
import {defineStore} from "pinia";
5-
import type {DateRange} from "~/types/date";
5+
import type {DateRange, DateRangeFilter} from "~/types/date";
66
import type { SelectApiItem } from "~/types/select";
77
import type { Activity } from "~/types/api/item/clubDependent/plugin/presence/activity";
88

99
export const usePresenceStore = defineStore('presence', () => {
1010
const selectedActivities: Ref<SelectApiItem<Activity>[]> = ref([])
1111
const selectedDate: Ref<Date|null> = ref(null)
12-
const selectedRange: Ref<DateRange|undefined> = ref({ start: dayjs().subtract(30, 'day').toDate(), end: new Date() })
12+
const selectedRange: Ref<DateRange|DateRangeFilter|undefined> = ref({ start: dayjs().subtract(30, 'day').toDate(), end: new Date() })
1313
const searchQuery: Ref<string> = ref('')
1414

1515
const totalExternal: Ref<number> = ref(0)

app/stores/useSaleStore.ts

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import MemberQuery from "~/composables/api/query/clubDependent/MemberQuery";
99
import {createBrowserCsvDownload} from "~/utils/browser";
1010
import {defineStore} from "pinia";
1111
import {ClubRole} from "~/types/api/item/club";
12-
import type {DateRange} from "~/types/date";
12+
import type {DateRange, DateRangeFilter} from "~/types/date";
1313

1414
export const useSaleStore = defineStore('sale', () => {
1515
const saleQuery = new SaleQuery()
@@ -18,7 +18,7 @@ export const useSaleStore = defineStore('sale', () => {
1818

1919
const isLoading = ref(false)
2020
const isDownloadingCsv = ref(false)
21-
const selectedRange: Ref<DateRange | undefined> = ref({start: new Date(), end: new Date()})
21+
const selectedRange: Ref<DateRange | DateRangeFilter | undefined> = ref({start: new Date(), end: new Date()})
2222
const lastRefreshDate: Ref<Date> = ref(new Date())
2323

2424
const shouldRefreshSales = ref(false)
@@ -39,15 +39,21 @@ export const useSaleStore = defineStore('sale', () => {
3939
page: page.toString(),
4040
});
4141

42-
const formattedStartDate = formatDateInput(selectedRange.value?.start.toString())
43-
const formattedEndDate = formatDateInput(dayjs(selectedRange.value?.end).add(1, 'days').toString())
44-
if (formattedStartDate) {
45-
urlParams.append(`createdAt[after]`, formattedStartDate);
46-
47-
if (formattedEndDate) {
48-
urlParams.append(`createdAt[before]`, formattedEndDate);
42+
if (selectedRange.value) {
43+
if (typeof selectedRange.value.value === 'string') {
44+
urlParams.append(`${selectedRange.value.value}[createdAt]`, 'true');
4945
} else {
50-
urlParams.append(`createdAt[before]`, formattedStartDate);
46+
const formattedStartDate = formatDateInput(selectedRange.value.start.toString())
47+
const formattedEndDate = formatDateInput(dayjs(selectedRange.value.end).add(1, 'days').toString())
48+
if (formattedStartDate) {
49+
urlParams.append(`createdAt[after]`, formattedStartDate);
50+
51+
if (formattedEndDate) {
52+
urlParams.append(`createdAt[before]`, formattedEndDate);
53+
} else {
54+
urlParams.append(`createdAt[before]`, formattedStartDate);
55+
}
56+
}
5157
}
5258
}
5359

@@ -81,15 +87,19 @@ export const useSaleStore = defineStore('sale', () => {
8187
});
8288

8389
if (selectedRange.value) {
84-
const formattedStartDate = formatDateInput(selectedRange.value.start.toString())
85-
const formattedEndDate = formatDateInput(dayjs(selectedRange.value.end).add(1, 'days').toString())
86-
if (formattedStartDate) {
87-
urlParams.append(`createdAt[after]`, formattedStartDate);
88-
89-
if (formattedEndDate) {
90-
urlParams.append(`createdAt[before]`, formattedEndDate);
91-
} else {
92-
urlParams.append(`createdAt[before]`, formattedStartDate);
90+
if (typeof selectedRange.value.value === 'string') {
91+
urlParams.append(`${selectedRange.value.value}[createdAt]`, 'true');
92+
} else {
93+
const formattedStartDate = formatDateInput(selectedRange.value.start.toString())
94+
const formattedEndDate = formatDateInput(dayjs(selectedRange.value.end).add(1, 'days').toString())
95+
if (formattedStartDate) {
96+
urlParams.append(`createdAt[after]`, formattedStartDate);
97+
98+
if (formattedEndDate) {
99+
urlParams.append(`createdAt[before]`, formattedEndDate);
100+
} else {
101+
urlParams.append(`createdAt[before]`, formattedStartDate);
102+
}
93103
}
94104
}
95105
} else {

app/types/date.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,8 @@ export interface DateRange {
22
start: Date
33
end: Date
44
}
5+
6+
export interface DateRangeFilter {
7+
label: string
8+
value: string
9+
}

app/utils/date.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import dayjs from "dayjs";
2-
import type {DateRange} from "~/types/date";
2+
import type {DateRange, DateRangeFilter} from "~/types/date";
33

44
export function formatDate(date?: string): string | null {
55
if (!date) return null;
@@ -19,10 +19,15 @@ export function formatDateReadable(date?: string): string | null {
1919
return new Date(date).toLocaleString('fr-FR', {day: 'numeric', month: 'long', year: 'numeric'});
2020
}
2121

22-
export function formatDateRangeReadable(dateRange?: DateRange): string | null {
22+
export function formatDateRangeReadable(dateRange?: DateRange|DateRangeFilter): string | null {
2323
if (!dateRange) return null;
2424
let response = '';
2525

26+
const isFilter = typeof dateRange.label === 'string';
27+
if (isFilter) {
28+
return dateRange.label
29+
}
30+
2631
if (dateRange.start) {
2732
response += formatDateReadable(dateRange.start.toString())
2833
}

0 commit comments

Comments
 (0)