From 70f6fdfa4074b8494231cf151ea89553f578bf3d Mon Sep 17 00:00:00 2001 From: Matthieu Petit Date: Thu, 26 Dec 2024 13:41:55 +0100 Subject: [PATCH] feat(attendance): draft attendance page --- README.md | 2 +- package.json | 52 +- ...ts+6.6.8.patch => vue-echarts+6.7.3.patch} | 23 +- src/assets/animations/empty-office.lottie | Bin 0 -> 2449 bytes .../animations/select-calendar-date.lottie | Bin 0 -> 2235 bytes src/components/CircularProgress.vue | 37 + src/components/LoadingProgressBar.vue | 27 + src/components/layout/NavigationDrawer.vue | 10 +- src/i18n/index.ts | 4 + src/i18n/locales/en-GB/attendance.json | 54 + src/i18n/locales/en-GB/index.ts | 1 + src/i18n/locales/en-GB/navigation.json | 1 + src/i18n/locales/fr-FR/attendance.json | 54 + src/i18n/locales/fr-FR/index.ts | 1 + src/i18n/locales/fr-FR/navigation.json | 1 + src/router/names.ts | 1 + src/router/routes.ts | 11 + src/services/api/activity.ts | 2 +- src/services/api/attendance.ts | 42 + src/services/api/members.ts | 2 +- .../Attendance/AttendanceCalendarTile.vue | 73 + .../Private/Attendance/AttendanceDetail.vue | 258 ++ .../Private/Attendance/AttendancePage.vue | 243 ++ .../Attendance/AttendingMemberCard.vue | 84 + src/views/Private/Members/MembersList.vue | 49 +- .../Stats/Incomes/StatsIncomesDaily.vue | 17 +- .../Stats/Incomes/StatsIncomesMonthly.vue | 23 +- .../Stats/Incomes/StatsIncomesPeriodGraph.vue | 20 +- .../Stats/Incomes/StatsIncomesWeekly.vue | 23 +- .../Stats/Incomes/StatsIncomesYearly.vue | 23 +- src/views/Private/User/UserProfile.vue | 2 + yarn.lock | 2151 +++++++++++++---- 32 files changed, 2735 insertions(+), 556 deletions(-) rename patches/{vue-echarts+6.6.8.patch => vue-echarts+6.7.3.patch} (65%) create mode 100644 src/assets/animations/empty-office.lottie create mode 100644 src/assets/animations/select-calendar-date.lottie create mode 100644 src/components/CircularProgress.vue create mode 100644 src/components/LoadingProgressBar.vue create mode 100644 src/i18n/locales/en-GB/attendance.json create mode 100644 src/i18n/locales/fr-FR/attendance.json create mode 100644 src/services/api/attendance.ts create mode 100644 src/views/Private/Attendance/AttendanceCalendarTile.vue create mode 100644 src/views/Private/Attendance/AttendanceDetail.vue create mode 100644 src/views/Private/Attendance/AttendancePage.vue create mode 100644 src/views/Private/Attendance/AttendingMemberCard.vue diff --git a/README.md b/README.md index 2bb1878..fb68a0e 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ If you are having problem during build, use [`patch-package`](https://github.com @@ -1,6 +1,14 @@ { "name": "vue-echarts", - "version": "6.6.8", + "version": "6.7.3", + "type": "module", + "exports": { + ".": { diff --git a/package.json b/package.json index c9bfeda..ef93c93 100644 --- a/package.json +++ b/package.json @@ -13,62 +13,62 @@ "serve": "docker run --rm --name tickets-manager-web-nginx -v $(pwd)/dist:/usr/share/nginx/html:ro -p9999:80 nginx" }, "dependencies": { - "@headlessui/vue": "^1.7.22", + "@headlessui/vue": "^1.7.23", "@intlify/unplugin-vue-i18n": "^4.0.0", "@jamescoyle/vue-icon": "^0.1.2", "@johanaarstein/dotlottie-player-light": "^1.0.13", "@mdi/js": "^7.4.47", - "@tanstack/vue-query": "^5.37.1", - "@unhead/vue": "^1.9.10", + "@tanstack/vue-query": "^5.62.12", + "@unhead/vue": "^1.11.14", "@vuelidate/core": "^2.0.3", "@vuelidate/validators": "^2.0.4", "@vueuse/core": "10.2.0", - "axios": "^1.7.0", - "axios-retry": "^4.2.0", - "dayjs": "^1.11.11", + "axios": "^1.7.9", + "axios-retry": "^4.5.0", + "dayjs": "^1.11.13", "echarts": "^5.5.0", "floating-vue": "^5.2.2", "lodash": "^4.17.21", - "pinia": "^2.1.7", + "pinia": "^2.3.0", "typeface-inter": "^3.18.1", "uuid": "^9.0.1", - "vue": "^3.4.27", - "vue-echarts": "6.6.8", + "vue": "^3.5.13", + "vue-echarts": "6.7.3", "vue-i18n": "^9.13.1", "vue-number-animation": "^2.0.2", - "vue-router": "^4.3.2", + "vue-router": "^4.5.0", "vue-tailwind-datepicker": "^1.7.3" }, "devDependencies": { "@intlify/eslint-plugin-vue-i18n": "^2.0.0", - "@tailwindcss/forms": "^0.5.7", - "@tailwindcss/typography": "^0.5.13", - "@types/lodash": "^4.17.4", + "@tailwindcss/forms": "^0.5.9", + "@tailwindcss/typography": "^0.5.15", + "@types/lodash": "^4.17.14", "@types/node": "^20.12.12", "@types/uuid": "^9.0.8", "@typescript-eslint/eslint-plugin": "^7.9.0", "@typescript-eslint/parser": "^7.9.0", - "@vitejs/plugin-vue": "^5.0.4", + "@vitejs/plugin-vue": "^5.2.1", "@vue/eslint-config-prettier": "^9.0.0", "@vue/eslint-config-typescript": "^13.0.0", - "autoprefixer": "^10.4.19", + "autoprefixer": "^10.4.20", "eslint": "^8", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsonc": "^2.15.1", - "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-tailwindcss": "^3.15.2", - "eslint-plugin-vue": "^9.26.0", - "eslint-plugin-vuejs-accessibility": "^2.3.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsonc": "^2.18.2", + "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-tailwindcss": "^3.17.5", + "eslint-plugin-vue": "^9.32.0", + "eslint-plugin-vuejs-accessibility": "^2.4.1", "patch-package": "^8.0.0", - "postcss": "^8.4.38", - "prettier": "^3.2.5", - "tailwindcss": "^3.4.3", - "typescript": "^5.4.5", + "postcss": "^8.4.49", + "prettier": "^3.4.2", + "tailwindcss": "^3.4.17", + "typescript": "^5.7.2", "vite": "^5.2.11", "vite-plugin-static-copy": "^1.0.5", - "vue-tsc": "^2.0.19" + "vue-tsc": "^2.2.0" } } diff --git a/patches/vue-echarts+6.6.8.patch b/patches/vue-echarts+6.7.3.patch similarity index 65% rename from patches/vue-echarts+6.6.8.patch rename to patches/vue-echarts+6.7.3.patch index 5b17fb2..6c7b7ad 100644 --- a/patches/vue-echarts+6.6.8.patch +++ b/patches/vue-echarts+6.7.3.patch @@ -1,22 +1,23 @@ diff --git a/node_modules/vue-echarts/dist/index.esm.js b/node_modules/vue-echarts/dist/index.esm.js -index 4ef9b7c..f05e046 100644 +index 3ec3ce0..c9e8af8 100644 --- a/node_modules/vue-echarts/dist/index.esm.js +++ b/node_modules/vue-echarts/dist/index.esm.js @@ -1,5 +1,5 @@ - import { watch, unref, inject, computed, watchEffect, Vue2, defineComponent, shallowRef, toRefs, getCurrentInstance, onMounted, onBeforeUnmount, h, nextTick } from 'vue-demi'; + import { watch, isRef, unref, inject, computed, watchEffect, Vue2, defineComponent, shallowRef, toRefs, getCurrentInstance, onMounted, onBeforeUnmount, h, nextTick } from 'vue-demi'; -import { throttle, init } from 'echarts/core'; +import { throttle, init } from 'echarts/core.js'; import { addListener, removeListener } from 'resize-detector'; - /****************************************************************************** + /****************************************************************************** diff --git a/node_modules/vue-echarts/package.json b/node_modules/vue-echarts/package.json -index 5fce2eb..5bafc62 100644 +index 7e46d29..dd07c39 100644 --- a/node_modules/vue-echarts/package.json +++ b/node_modules/vue-echarts/package.json -@@ -1,6 +1,14 @@ - { - "name": "vue-echarts", - "version": "6.6.8", +@@ -87,5 +87,13 @@ + "build:demo": "vue-cli-service build", + "docs": "node ./scripts/docs.js", + "postinstall": "node ./scripts/postinstall.js" ++ }, + "type": "module", + "exports": { + ".": { @@ -24,7 +25,5 @@ index 5fce2eb..5bafc62 100644 + "import": "./dist/index.esm.js", + "types": "./dist/index.d.ts" + } -+ }, - "description": "Vue.js component for Apache ECharts.", - "author": "GU Yiling ", - "scripts": { + } + } diff --git a/src/assets/animations/empty-office.lottie b/src/assets/animations/empty-office.lottie new file mode 100644 index 0000000000000000000000000000000000000000..eeb1ebb978dbf035cf169d8eeadb32e98f78d4d7 GIT binary patch literal 2449 zcmbW3X*d*&7RLuOvNQH%E%RDxn9*ov(qe{$K}Mv;P-Gi1S*Nm;VeGqxY)OMxh|s2G zY?-nYvNl<=Gm|x8Bz3*_%f0XWJon2z=Q+Vk!4Wvr6@_qvqFhmE zn4u@a5O&1v-)}8CUAQ`RMC#YU*g{D5X2x^*<1QjkjFTFG+vB6CD+f~jKG_Vj_Wx#n zNk1B)?N^6)K)#BE1e(3kKqGUz*~@GP&m7nNosWn8C=dbB)F8c*>C}T6UP;yz)|zih z+>DrdSLtBKK8bNPcGg5>SLYm8^}FY0{!W=&E%C&{#xUn*tqYa+;e&O_;n79UZD&fz zj$U_m-^=Ls!>L=E zeL@-z6M3&R@o zxWu$adktQ2y|F?N^${cmN1nfMx%LmpMWyh&Y}D-yanV)PWXH_)<1{Yf%Sqp|{H;j= zlvcrQ-(^yY0>~Sjd#fMhlB@*o4K~`@Oo)41oiJm2a6|dGgg@fWWBNZ6udf zjxL6V-8&u?(`D92sDgRLh$kI>ICR*CGmWiQJ92lun6%E0RB4rOGQT7Ls<=b3rm6$^ zcy#n8bBp`Q)aqvFCw+y3+Mosi%kixLjC$G}a^&mCD=paq`j5SdDhfapxF%ml-4C1R zdK?I&O0t8a6fF$Q8|NS7v%shgx}U$`P2;JnX zqlCew^(l86yXI6p!_I zT4O@A*jdKpSG(zp8yzPJSHJx}dFNJ4NS%W2PKDzS@Ouf(9U-j5Btx;dA3wl{+9*hB z3ia3FH!`#7(BJVs%^XO$pds(>6-|IEt;QB|Cg~Ha#~kycA>nD zA~?A;_B03tk#+rE54;FV(`1uoy;t=tSF9h6=T8vN)bUd7+^P0#R>9o`t6+JmyMwpE zL``8{35X%>L?al*^-o*9q*)F~BA9DHIV(F_bcb`*S%9v6NP3~@{y0zLXQ?)7Owm|; z2LC2}>-2p|h6om4Zk%|)%&jHc+G0={@1Scij!QN_AOM2wX&JJuJ7wHu(lvQ&NS~>a@=(WUkR`9Nh!xF#r1GCuNzlgJYDwZK47n-A`=r= z83*X{A;PF4rMddz?GNccrXR{EnfGs+6Abr}h1!>54nQguBVi z%!j;>GncajYSifH8*zIQqwMWL*58QN*UaNYQVtK5RCcJ(n%EL<$ru&Ihn)T?7~sDn z4rXcMDxzZ}b+sRqnG{-R6a~j~pqa*3E?0qZg56#zZ!*}54g+yG91r`bB6jHH{?q8S z5kG~apzE&|zfp!~7N2$AntCQ0Twm4E$$Gc-D{JYcRG^6P0|DEGYDd}ARO&b8XDU!G zyI%{#QRzV_^jf9PCXs~c@8T6*8*_4gWEOBTAMdY?RaI;V^a|+2tA{@jtdt$6v-%4W z=IaEjW@x%uV2t*RF>1g9o&MGW&fXY%N|w19+~@UMVaX5A(KD|}fY zx|kwPGzJvuM06@b@YggkpGsK5PLw;&=sl(RWHB(bON#E;@@_j4 zqoWgmPjD(|No)JFpo&h6vfh%0&z!8&F>bg=Uhe%;#ti!@YK!CJmj(Q9zS%{F|BAoS i&OcZGi5maetJxj@AMminfdv1$!oQn$cl(&oU+Q1jHd|f* literal 0 HcmV?d00001 diff --git a/src/assets/animations/select-calendar-date.lottie b/src/assets/animations/select-calendar-date.lottie new file mode 100644 index 0000000000000000000000000000000000000000..18d164e785f64c88654472c138f5c04af35deeff GIT binary patch literal 2235 zcmbVOXE+;-7LKS@qeen)r6@5%j3{arA8n1+UI`kaD#VUeBSK=2wi;^JDvC>uqO_>J z_o|WFt6EweKHvRw@Ao~={d3QG-shb2<2}!Ne!a)Ui24Eu007VfBojn!I>UT?@#jy_fUN z!I(pewJ_6$(vc2$0@A%i+OYS@hsW)V0(2o2TynN@QnWhTR@H!U;AW%4(@hh2`} zY3TrfJtY7@;au;z+=obCG{)0M7OCW-B8P;@NxLX0qNEj^U@&R8vx>Yl9Oo2hTb64{w$7AWzt6_hLmSQDk)BEsK9zuOUS|#2m56;w!i!za@ z%ZRFJ(oEl@LW}Z=tucLAtn5tNOc3fRBGNU;zwyH$c&PSJO|`p^Nw#BkK-wX@zn0CR zsJC`g5x2mi!K5*=Fa6t-@Xom9yPFcf_CR-%pz|4N=4(i1_Q?`u#^oTWA@{_wZ1NCP zB|K!2Bj=WP^qSmL$d&8FU^MKHmvOA&wx_KgGv7KDwCS{eu2oimFQ9obWplc?ZUam6 znbwwP7j~;49q_f?gl#73RFP@cgAN_(XH?CAt2P3wcB)<86fMKeTr`+h0}%tQpinhr zsO2(V`e~TBg`W8F3#G_yOfZ5w->_mT9;PDf958a9unr|ZYY=iS(}YAL==~Cjr7;rt zA}wjZtPZu`4sX_d##@U6uaJlDY;RqQ_NY`}?bXv@F@mnXSmxbu3R%+mJxC0^u@_m}q?61~teAFX0ORV%l>1km=h`11VC{;tEsl zqT5BnKCw-tWGnEvu)WLT6WG;PCB$CCYELIgzZ*4C5r*FNLiz@t5%DJ*oeCNwpifUZ)%#FLX$F+?`lih zNL_T*n+t$u{%qXa7|UnW$}i<~hHK3h5=FajhQ&;nxeySk1itIbqgHD%rw|bX zzai~})HQH-oKf<-c83HTl>`zzRc6_I!&^sV)n@~sUI?)n z1-AwVGFDShz7xZuQD`U5SHRyTcEzuz)XZ~UG(DeAxdTGZsf?WRaQR|n{{-S`=D~4F?1Ys;t4Ev2(H~X7P?K94i zycOHqwpt?Xqs%1b%0l%yamS|2rXD=I$?q;M2n2*KA*=O^1Rt2Q)->%0ZdN!%?I!uw z(wPVZ))MR;x>3dgp0&l991R(KcvP&dUZ`D~u5AHh|*;Bk!6-H8<$v6aNK~_0LD2K5hufY}zJTXSa*~hP| z+{1tT60%%rycc0d^F$Dgy|0Wt#KPA+<(D01rK>|V7VTXlrQfMX28dW~BjUZn==aSC zF&!K@$K-$(C&LbkKHgy>!6EPm}9 zF_i7%(hhI1uF3OdYDsEVbQU&OfABsYSTc%ac=#&EEJ$=%=Jgu+v{i8Y%5|2WCk7#$ zaku&AsKw@(uZP5jxeeFJ)pf-m!B-xYv{Q)@1A)5cx2PPS`VhaZ6TkUM2^!^&Nkk=T zcGGDPT)8~fg!L6J=abcKR6AtcXG-f<_*pLuP8I0{dN*4h^fn30#l5F$Zcx9~SyNYj zk65oLK{$#Egs1h2N4E-zGZ0|u-Nzf_0XkqhMiv_LEG=df^Hs@CpW$oDwy6lZ;0&h> zP3EHewx#v&OFF3R=P}C#ixq>SKHeeJlwdjk6dHVGA#_ygqXw1 z{=`~Otsf2_%<`^ok? literal 0 HcmV?d00001 diff --git a/src/components/CircularProgress.vue b/src/components/CircularProgress.vue new file mode 100644 index 0000000..a7eaee8 --- /dev/null +++ b/src/components/CircularProgress.vue @@ -0,0 +1,37 @@ + + + + + + diff --git a/src/components/LoadingProgressBar.vue b/src/components/LoadingProgressBar.vue new file mode 100644 index 0000000..fcd3b2e --- /dev/null +++ b/src/components/LoadingProgressBar.vue @@ -0,0 +1,27 @@ + + + + diff --git a/src/components/layout/NavigationDrawer.vue b/src/components/layout/NavigationDrawer.vue index 6e161f3..7ccf7b7 100644 --- a/src/components/layout/NavigationDrawer.vue +++ b/src/components/layout/NavigationDrawer.vue @@ -48,7 +48,7 @@ import { doesRouteBelongsTo } from '@/router/helpers'; import { ROUTE_NAMES } from '@/router/names'; import { useAuthStore } from '@/store/auth'; import MembersThumbnail from '@/views/Private/Members/MembersThumbnail.vue'; -import { mdiAccountGroup, mdiFinance, mdiHistory } from '@mdi/js'; +import { mdiAccountGroup, mdiCalendarMultiselect, mdiFinance, mdiHistory } from '@mdi/js'; import { computed } from 'vue'; import { useI18n } from 'vue-i18n'; import { RouteLocationRaw, useRoute } from 'vue-router'; @@ -88,5 +88,13 @@ const sidebarNavigation = computed(() => [ icon: mdiHistory, active: doesRouteBelongsTo(route, ROUTE_NAMES.HISTORY), }, + { + label: i18n.t('navigation.attendance'), + to: { + name: ROUTE_NAMES.ATTENDANCE, + }, + icon: mdiCalendarMultiselect, + active: doesRouteBelongsTo(route, ROUTE_NAMES.ATTENDANCE), + }, ]); diff --git a/src/i18n/index.ts b/src/i18n/index.ts index ac2961c..a2ceafe 100644 --- a/src/i18n/index.ts +++ b/src/i18n/index.ts @@ -2,11 +2,13 @@ import { LOCALE_STORAGE_KEY } from '@/store/settings'; import { createI18nMessage } from '@vuelidate/validators'; import dayjs from 'dayjs'; import calendar from 'dayjs/plugin/calendar.js'; +import customParseFormat from 'dayjs/plugin/customParseFormat.js'; import duration from 'dayjs/plugin/duration.js'; import isBetween from 'dayjs/plugin/isBetween.js'; import LocalizedFormat from 'dayjs/plugin/localizedFormat.js'; import relativeTime from 'dayjs/plugin/relativeTime.js'; import updateLocale from 'dayjs/plugin/updateLocale.js'; +import weekday from 'dayjs/plugin/weekday.js'; import { createI18n, IntlDateTimeFormats, IntlNumberFormats, PluralizationRule } from 'vue-i18n'; import 'dayjs/locale/fr.js'; import 'dayjs/locale/en-gb.js'; @@ -16,6 +18,8 @@ dayjs.extend(relativeTime); dayjs.extend(LocalizedFormat); dayjs.extend(duration); dayjs.extend(isBetween); +dayjs.extend(customParseFormat); +dayjs.extend(weekday); dayjs.updateLocale('fr', { calendar: { diff --git a/src/i18n/locales/en-GB/attendance.json b/src/i18n/locales/en-GB/attendance.json new file mode 100644 index 0000000..5425156 --- /dev/null +++ b/src/i18n/locales/en-GB/attendance.json @@ -0,0 +1,54 @@ +{ + "calendar": { + "tile": { + "attending": "No one | {count} attendee | {count} attendees", + "debt": "No debt | {count} overconsumed | {count} overconsumed" + } + }, + "description": "Who was there? Who did what? Who owes money?", + "detail": { + "activity": { + "value": { + "FULL": "1 full day", + "HALF": "1 half-day", + "NONE": "absent" + } + }, + "attending": "No attendees | 1 attendee | {count} attendees", + "empty": { + "description": "Apparently, no one showed up on this day.", + "title": "No one" + }, + "search": { + "empty": { + "title": "No results" + }, + "label": "Search for a member", + "placeholder": "@:attendance.detail.search.label" + }, + "select": { + "description": "To view attendance and other details for a specific day.", + "title": "Select a date" + }, + "sort": { + "label": "Sort {suffix}", + "value": { + "activity": "By activity", + "debt": "By debt", + "name": "By name" + } + } + }, + "head": { + "title": "@:attendance.title" + }, + "navigation": { + "nextMonth": "Next month", + "previousMonth": "Previous month", + "today": "Today" + }, + "onFetch": { + "fail": "Unable to retrieve attendance for the period from {start} to {end}" + }, + "title": "Attendance" +} diff --git a/src/i18n/locales/en-GB/index.ts b/src/i18n/locales/en-GB/index.ts index 6f05379..1ef0a8b 100644 --- a/src/i18n/locales/en-GB/index.ts +++ b/src/i18n/locales/en-GB/index.ts @@ -11,3 +11,4 @@ export { default as tickets } from './tickets.json'; export { default as activity } from './activity.json'; export { default as errors } from './errors.json'; export { default as audit } from './audit.json'; +export { default as attendance } from './attendance.json'; diff --git a/src/i18n/locales/en-GB/navigation.json b/src/i18n/locales/en-GB/navigation.json index a7a6f91..f2c8647 100644 --- a/src/i18n/locales/en-GB/navigation.json +++ b/src/i18n/locales/en-GB/navigation.json @@ -1,4 +1,5 @@ { + "attendance": "@:attendance.title", "close": "Close menu", "history": "@:audit.list.title", "members": "@:members.list.title", diff --git a/src/i18n/locales/fr-FR/attendance.json b/src/i18n/locales/fr-FR/attendance.json new file mode 100644 index 0000000..f8f89f2 --- /dev/null +++ b/src/i18n/locales/fr-FR/attendance.json @@ -0,0 +1,54 @@ +{ + "calendar": { + "tile": { + "attending": "Personne | {count} présent | {count} présents", + "debt": "Aucune dette | {count} surconsommé | {count} surconsommés" + } + }, + "description": "Qui était là ? Qui a fait quoi ? Qui doit de la moula ?", + "detail": { + "activity": { + "value": { + "FULL": "1 journée complète", + "HALF": "1 demi-journée", + "NONE": "absent" + } + }, + "attending": "Aucun présent | 1 seul présent | {count} présents", + "empty": { + "description": "Apparemment, personne ne s'est présenté ce jour-ci.", + "title": "Personne" + }, + "search": { + "empty": { + "title": "Aucun résultat" + }, + "label": "Rechercher un membre", + "placeholder": "@:attendance.detail.search.label" + }, + "select": { + "description": "Pour visualiser les présences et autres informations d'un jour précis.", + "title": "Sélectionner une date" + }, + "sort": { + "label": "Trier {suffix}", + "value": { + "activity": "Par activité", + "debt": "Par dette", + "name": "Par nom" + } + } + }, + "head": { + "title": "@:attendance.title" + }, + "navigation": { + "nextMonth": "Mois suivant", + "previousMonth": "Mois précédent", + "today": "Aujourd'hui" + }, + "onFetch": { + "fail": "Impossible de récupérer les présences pour la période du {start} au {end}" + }, + "title": "Présence" +} diff --git a/src/i18n/locales/fr-FR/index.ts b/src/i18n/locales/fr-FR/index.ts index 6f05379..1ef0a8b 100644 --- a/src/i18n/locales/fr-FR/index.ts +++ b/src/i18n/locales/fr-FR/index.ts @@ -11,3 +11,4 @@ export { default as tickets } from './tickets.json'; export { default as activity } from './activity.json'; export { default as errors } from './errors.json'; export { default as audit } from './audit.json'; +export { default as attendance } from './attendance.json'; diff --git a/src/i18n/locales/fr-FR/navigation.json b/src/i18n/locales/fr-FR/navigation.json index c67f5cf..ee2b9b2 100644 --- a/src/i18n/locales/fr-FR/navigation.json +++ b/src/i18n/locales/fr-FR/navigation.json @@ -1,4 +1,5 @@ { + "attendance": "@:attendance.title", "close": "Fermer le menu", "history": "@:audit.list.title", "members": "@:members.list.title", diff --git a/src/router/names.ts b/src/router/names.ts index 90eb7ad..28504d3 100644 --- a/src/router/names.ts +++ b/src/router/names.ts @@ -4,6 +4,7 @@ import { flatMapDeep, isEqual } from 'lodash'; const RAW_ROUTE_NAMES = { LOGIN: 'LOGIN', HISTORY: 'HISTORY', + ATTENDANCE: 'ATTENDANCE', STATS: { INDEX: 'STATS.INDEX', INCOMES: { diff --git a/src/router/routes.ts b/src/router/routes.ts index d9918b2..9e7d8b9 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -213,6 +213,17 @@ export const routes: RouteRecordRaw[] = [ to: route.query.to, }), }, + { + path: 'attendance/:date?', + name: ROUTE_NAMES.ATTENDANCE, + component: () => import('@/views/Private/Attendance/AttendancePage.vue'), + props: (route) => ({ + month: route.query.month, + date: route.params.date, + search: route.query.search, + sort: route.query.sort, + }), + }, { path: 'profile', name: ROUTE_NAMES.USER.PROFILE, diff --git a/src/services/api/activity.ts b/src/services/api/activity.ts index c34bb4b..8a0547b 100644 --- a/src/services/api/activity.ts +++ b/src/services/api/activity.ts @@ -1,6 +1,6 @@ import HTTP from '../http'; -export const MAX_ATTENDANCE = 28; +export const MAX_ATTENDANCE = 40; export type ActivityPeriod = { date: string; diff --git a/src/services/api/attendance.ts b/src/services/api/attendance.ts new file mode 100644 index 0000000..8bb2d40 --- /dev/null +++ b/src/services/api/attendance.ts @@ -0,0 +1,42 @@ +import { MemberListItem } from './members'; +import HTTP from '../http'; + +export const MAX_ATTENDANCE = 40; + +export type AttendingMember = MemberListItem & { + attendance: { + tickets: { + count: number; // tickets count consumed + amount: number; // amount in euro + debt: { + count: number; // tickets count consumed when not paid yet + amount: number; // debt in euro + }; + }; + subscriptions: { + count: number; // subscriptions count + amount: number; // amount in euro + }; + }; +}; + +export type AttendancePeriod = { + date: string; + type: PeriodType; + data: { + members: AttendingMember[]; + }; +}; + +export const getAttendancePerDay = ( + from?: string, + to?: string, +): Promise[]> => { + return HTTP.get('/stats/attendance/day', { + params: { + ...(from && { from }), + ...(to && { to }), + }, + timeout: 30_000, + }).then(({ data }) => data); +}; diff --git a/src/services/api/members.ts b/src/services/api/members.ts index 4f539fc..7fdd9f0 100644 --- a/src/services/api/members.ts +++ b/src/services/api/members.ts @@ -4,7 +4,7 @@ import HTTP from '../http'; import dayjs from 'dayjs'; export type AttendanceType = 'subscription' | 'ticket'; -export type MemberLocation = 'poulailler' | 'pti-poulailler' | 'racine'; +export type MemberLocation = 'poulailler' | 'pti-poulailler' | 'racine' | 'cantina'; export interface Attendance { date: string; diff --git a/src/views/Private/Attendance/AttendanceCalendarTile.vue b/src/views/Private/Attendance/AttendanceCalendarTile.vue new file mode 100644 index 0000000..2d2a059 --- /dev/null +++ b/src/views/Private/Attendance/AttendanceCalendarTile.vue @@ -0,0 +1,73 @@ + + + diff --git a/src/views/Private/Attendance/AttendanceDetail.vue b/src/views/Private/Attendance/AttendanceDetail.vue new file mode 100644 index 0000000..5be17b4 --- /dev/null +++ b/src/views/Private/Attendance/AttendanceDetail.vue @@ -0,0 +1,258 @@ + + + diff --git a/src/views/Private/Attendance/AttendancePage.vue b/src/views/Private/Attendance/AttendancePage.vue new file mode 100644 index 0000000..3d81186 --- /dev/null +++ b/src/views/Private/Attendance/AttendancePage.vue @@ -0,0 +1,243 @@ + + + diff --git a/src/views/Private/Attendance/AttendingMemberCard.vue b/src/views/Private/Attendance/AttendingMemberCard.vue new file mode 100644 index 0000000..5abd74f --- /dev/null +++ b/src/views/Private/Attendance/AttendingMemberCard.vue @@ -0,0 +1,84 @@ + + + diff --git a/src/views/Private/Members/MembersList.vue b/src/views/Private/Members/MembersList.vue index 39e5239..f71a9e0 100644 --- a/src/views/Private/Members/MembersList.vue +++ b/src/views/Private/Members/MembersList.vue @@ -124,29 +124,33 @@
-
    - - -
  • - - - -
  • -
+ +