From 2095964ac3da2f00900a188a4ec7b28929121e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20LeBlanc?= Date: Tue, 10 Oct 2023 00:38:09 -0400 Subject: [PATCH] Fix bugs --- nuxt.config.ts | 1 - package.json | 1 - src/components/TimeEntry.vue | 6 +- src/stores/index.ts | 582 +++++++++++++++++------------------ yarn.lock | 16 +- 5 files changed, 289 insertions(+), 317 deletions(-) diff --git a/nuxt.config.ts b/nuxt.config.ts index 60a158e..82131d7 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -13,7 +13,6 @@ export default defineNuxtConfig({ '@nuxtjs/color-mode', '@nuxtjs/google-fonts', '@pinia/nuxt', - '@pinia-plugin-persistedstate/nuxt', '@vueuse/nuxt', 'nuxt-vuefire', ], diff --git a/package.json b/package.json index 8eac054..4a6a35a 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "@nuxtjs/google-fonts": "^3.0.0-1", "@nuxtjs/i18n": "^8.0.0-beta.9", "@nuxtjs/tailwindcss": "^6.2.0", - "@pinia-plugin-persistedstate/nuxt": "^1.0.0", "@types/inputmask": "^5.0.3", "@types/moment-duration-format": "^2.2.3", "@vueuse/components": "^10.3.0", diff --git a/src/components/TimeEntry.vue b/src/components/TimeEntry.vue index 595f829..e43336a 100644 --- a/src/components/TimeEntry.vue +++ b/src/components/TimeEntry.vue @@ -224,7 +224,7 @@ const emit = defineEmits<{ (e: 'add'): void; }>(); -const model = ref(JSON.parse(JSON.stringify(props.entry))); +const model = ref(Object.create(null, Object.getOwnPropertyDescriptors(props.entry))); const placeholder = ref('00:00:00'); const computedDate = computed(() => { @@ -379,7 +379,7 @@ function start() { function stop() { model.value.end_time = model.value.end_time || $moment().format('HH:mm'); model.value.is_live_clocking = false; - updateEntry(model.value, props.entry); + updateEntry(model.value); } function add() { @@ -391,7 +391,7 @@ function add() { function edit() { model.value.is_creating = false; model.value.is_editing = false; - updateEntry(model.value, props.entry); + updateEntry(model.value); } function cancel() { diff --git a/src/stores/index.ts b/src/stores/index.ts index 8ee9f2c..b9f1b42 100644 --- a/src/stores/index.ts +++ b/src/stores/index.ts @@ -3,327 +3,315 @@ import { collection, addDoc, updateDoc, deleteDoc, doc, query, where, writeBatch import type { QueryDocumentSnapshot, SnapshotOptions, DocumentData } from 'firebase/firestore'; import { firestoreDefaultConverter } from 'vuefire'; -export const useIndexStore = defineStore( - 'store', - () => { - const db = useFirestore(); - const user = useCurrentUser(); - const nuxtApp = useNuxtApp(); - const { $moment } = nuxtApp; - const { t } = nuxtApp.$i18n; +export const useIndexStore = defineStore('store', () => { + const db = useFirestore(); + const user = useCurrentUser(); + const nuxtApp = useNuxtApp(); + const { $moment } = nuxtApp; + const { t } = nuxtApp.$i18n; - const dateConverter = { - toFirestore(entry: Entry): DocumentData { - delete entry.id; - return { - ...entry, - date: $moment(entry.date).startOf('day').toDate(), - }; - }, - fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions): DocumentData { - const data = firestoreDefaultConverter.fromFirestore(snapshot)!; - data.date = $moment(data.date.toDate()).format('YYYY-MM-DD'); - return data; - }, - }; + const dateConverter = { + toFirestore(entry: Entry): DocumentData { + delete entry.id; + return { + ...entry, + date: $moment(entry.date).startOf('day').toDate(), + }; + }, + fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions): DocumentData { + const data = firestoreDefaultConverter.fromFirestore(snapshot)!; + data.date = $moment(data.date.toDate()).format('YYYY-MM-DD'); + return data; + }, + }; - const selectedDay = ref(new Date().toLocaleDateString('en-CA')); - const menuOpened = ref(false); - const filter = ref('daily'); - const selectedTabIndex = ref(0); - const sort = ref('entries'); - const weekObjective = ref('40:00'); + const selectedDay = useLocalStorage('selectedDay', ref(new Date().toLocaleDateString('en-CA'))); + const filter = useLocalStorage('filter', ref('daily')); + const selectedTabIndex = useLocalStorage('selectedTabIndex', ref(0)); + const sort = useLocalStorage('entries', ref('entries')); + const weekObjective = useLocalStorage('weekObjective', ref('40:00')); + const menuOpened = ref(false); - const weekStart = computed(() => { - return $moment(selectedDay.value).startOf('week').toDate(); - }); - const weekEnd = computed(() => { - return $moment(selectedDay.value).endOf('week').toDate(); - }); - const projects = useCollection( - query(collection(db, 'projects'), where('user', '==', user.value?.uid)), - { - ssrKey: 'projects', - }, - ); - const priorities = useCollection( - query(collection(db, 'priorities'), where('user', '==', user.value?.uid)), - { - ssrKey: 'priorities', - }, - ); - const entries = useCollection( - computed(() => - query( - collection(db, 'entries').withConverter(dateConverter), - where('user', '==', user.value?.uid), - where('date', '>=', weekStart.value), - where('date', '<=', weekEnd.value), - ), + const weekStart = computed(() => { + return $moment(selectedDay.value).startOf('week').toDate(); + }); + const weekEnd = computed(() => { + return $moment(selectedDay.value).endOf('week').toDate(); + }); + const projects = useCollection(query(collection(db, 'projects'), where('user', '==', user.value?.uid)), { + ssrKey: 'projects', + }); + const priorities = useCollection( + query(collection(db, 'priorities'), where('user', '==', user.value?.uid)), + { + ssrKey: 'priorities', + }, + ); + const entries = useCollection( + computed(() => + query( + collection(db, 'entries').withConverter(dateConverter), + where('user', '==', user.value?.uid), + where('date', '>=', weekStart.value), + where('date', '<=', weekEnd.value), ), - { - ssrKey: 'entries', - }, - ); + ), + { + ssrKey: 'entries', + }, + ); - const todaysEntries = computed((): Entry[] => { - return [...entries.value] - .sort((a, b) => { - const startA = $moment(a.date + ' ' + a.start_time, 'YYYY-M-D HH:mm'); - const startB = $moment(b.date + ' ' + b.start_time, 'YYYY-M-D HH:mm'); - return startB.isBefore(startA) ? 1 : -1; - }) - .filter((e) => $moment(selectedDay.value).isSame(e.date, 'day')); + const todaysEntries = computed((): Entry[] => { + return [...entries.value] + .sort((a, b) => { + const startA = $moment(a.date + ' ' + a.start_time, 'YYYY-M-D HH:mm'); + const startB = $moment(b.date + ' ' + b.start_time, 'YYYY-M-D HH:mm'); + return startB.isBefore(startA) ? 1 : -1; + }) + .filter((e) => $moment(selectedDay.value).isSame(e.date, 'day')); + }); + const weekTotal = computed((): string => { + const total = Object.values(weekSummary.value).reduce((acc: moment.Duration, day: string) => { + acc = $moment.duration(acc).add($moment.duration(day)); + return acc; + }, $moment.duration()); + return $moment.duration(total).format('HH:mm', { + trim: false, }); - const weekTotal = computed((): string => { - const total = Object.values(weekSummary.value).reduce((acc: moment.Duration, day: string) => { - acc = $moment.duration(acc).add($moment.duration(day)); - return acc; - }, $moment.duration()); - return $moment.duration(total).format('HH:mm', { - trim: false, - }); - }); - const weekRemaining = computed((): string => { - return $moment.duration(weekObjective.value).subtract($moment.duration(weekTotal.value)).format('HH:mm', { - trim: false, - }); + }); + const weekRemaining = computed((): string => { + return $moment.duration(weekObjective.value).subtract($moment.duration(weekTotal.value)).format('HH:mm', { + trim: false, }); - const weekSummary = computed((): Summary => { - return entries.value - .filter((e) => !e.is_creating) - .filter((e) => $moment(e.date).isBetween(weekStart.value, weekEnd.value, 'day', '[]')) - .reduce( - (acc: Summary, e: Entry) => { - const day = $moment(e.date).locale('en').format('dddd').toLowerCase() as keyof Summary; - acc[day] = $moment.duration(acc[day]).add($moment.duration(e.duration)).format('HH:mm', { - trim: false, - }); + }); + const weekSummary = computed((): Summary => { + return entries.value + .filter((e) => !e.is_creating) + .filter((e) => $moment(e.date).isBetween(weekStart.value, weekEnd.value, 'day', '[]')) + .reduce( + (acc: Summary, e: Entry) => { + const day = $moment(e.date).locale('en').format('dddd').toLowerCase() as keyof Summary; + acc[day] = $moment.duration(acc[day]).add($moment.duration(e.duration)).format('HH:mm', { + trim: false, + }); - return acc; - }, - { - sunday: '00:00', - monday: '00:00', - tuesday: '00:00', - wednesday: '00:00', - thursday: '00:00', - friday: '00:00', - saturday: '00:00', - } as Summary, - ); - }); - const weeklySummaryByProjects = computed((): [string, string][] => { - const projects = [...entries.value] - .filter((e) => !e.is_creating) - // .filter((e) => $moment(e.date).isBetween(weekStart, weekEnd, 'day', '[]')) - .reduce((acc: { [key: string]: string }, e: Entry) => { - const project = e.project; - - if (!acc[project.name]) { - acc[project.name] = e.duration; - } else { - acc[project.name] = $moment.duration(acc[project.name]).add(e.duration).format('HH:mm', { - trim: false, - }); - } return acc; - }, {}); - - return Object.entries(projects).sort((a, b) => { - return $moment.duration(b[1]).asMilliseconds() - $moment.duration(a[1]).asMilliseconds(); - }); - }); - const dailySummaryByProjects = computed((): [string, string][] => { - const projects = [...entries.value] - .filter((e) => !e.is_creating) - .filter((e) => $moment(e.date).isSame(selectedDay.value)) - .reduce((acc: { [key: string]: string }, e: Entry) => { - const project = e.project; + }, + { + sunday: '00:00', + monday: '00:00', + tuesday: '00:00', + wednesday: '00:00', + thursday: '00:00', + friday: '00:00', + saturday: '00:00', + } as Summary, + ); + }); + const weeklySummaryByProjects = computed((): [string, string][] => { + const projects = [...entries.value] + .filter((e) => !e.is_creating) + // .filter((e) => $moment(e.date).isBetween(weekStart, weekEnd, 'day', '[]')) + .reduce((acc: { [key: string]: string }, e: Entry) => { + const project = e.project; - if (!acc[project.name]) { - acc[project.name] = e.duration; - } else { - acc[project.name] = $moment.duration(acc[project.name]).add(e.duration).format('HH:mm', { - trim: false, - }); - } - return acc; - }, {}); + if (!acc[project.name]) { + acc[project.name] = e.duration; + } else { + acc[project.name] = $moment.duration(acc[project.name]).add(e.duration).format('HH:mm', { + trim: false, + }); + } + return acc; + }, {}); - return Object.entries(projects).sort((a, b) => { - return $moment.duration(b[1]).asMilliseconds() - $moment.duration(a[1]).asMilliseconds(); - }); + return Object.entries(projects).sort((a, b) => { + return $moment.duration(b[1]).asMilliseconds() - $moment.duration(a[1]).asMilliseconds(); }); - const sortedProjects = computed((): [Project, number][] => { - // TODO: Sort by creation date - const p = projects.value.map((p): [Project, number] => [p, projectEntriesTotal(p)]); - if (sort.value === 'name') { - return p.sort((a, b) => { - return a[0].name.localeCompare(b[0].name); - }); - } - return p; - }); - const isLiveClockingEntry = computed((): boolean => { - return !!entries.value.find((e) => e.is_live_clocking); - }); - const isCreatingEntry = computed((): boolean => { - return !!entries.value.find((e) => e.is_creating); - }); - const canCreateEntry = computed((): boolean => { - return !isLiveClockingEntry.value && !isCreatingEntry.value; - }); - - const weekSummaryColors = (time: string): string => { - const isZero = $moment.duration(time).asHours() === 0; - const isOvertime = $moment.duration(time).asHours() >= $moment.duration(weekObjective.value).asHours() / 5; - const isBelow = - $moment.duration(time).asHours() >= $moment.duration(weekObjective.value).asHours() / 5 - 0.5; + }); + const dailySummaryByProjects = computed((): [string, string][] => { + const projects = [...entries.value] + .filter((e) => !e.is_creating) + .filter((e) => $moment(e.date).isSame(selectedDay.value)) + .reduce((acc: { [key: string]: string }, e: Entry) => { + const project = e.project; - if (isZero) { - return 'text-gray-400 dark:text-gray-600'; - } else if (isOvertime) { - return 'text-green-500'; - } else if (isBelow) { - return 'text-yellow-500'; - } else { - return 'text-red-500'; - } - }; - const projectEntriesTotal = (project: Project) => { - return entries.value.filter((e) => e?.project?.id === project.id).length; - }; + if (!acc[project.name]) { + acc[project.name] = e.duration; + } else { + acc[project.name] = $moment.duration(acc[project.name]).add(e.duration).format('HH:mm', { + trim: false, + }); + } + return acc; + }, {}); - async function addEntry(entry: Entry) { - await addDoc(collection(db, 'entries').withConverter(dateConverter), { - ...entry, - user: user.value?.uid, - project: doc(db, 'projects', entry.project.id), - }); - } - async function updateEntry(updatedEntry: Entry, originalEntry: Entry) { - await updateDoc(doc(db, 'entries', originalEntry.id), { - ...updatedEntry, - project: doc(db, 'projects', updatedEntry.project.id), - date: $moment(updatedEntry.date).startOf('day').toDate(), + return Object.entries(projects).sort((a, b) => { + return $moment.duration(b[1]).asMilliseconds() - $moment.duration(a[1]).asMilliseconds(); + }); + }); + const sortedProjects = computed((): [Project, number][] => { + // TODO: Sort by creation date + const p = projects.value.map((p): [Project, number] => [p, projectEntriesTotal(p)]); + if (sort.value === 'name') { + return p.sort((a, b) => { + return a[0].name.localeCompare(b[0].name); }); } - async function deleteEntry(entry: Entry, force = false) { - if (force || confirm(t('Êtes vous certain de vouloir supprimer cette entrée ?'))) { - await deleteDoc(doc(db, 'entries', entry.id)); - } - } - async function toggleEntrySynced(entry: Entry) { - await updateDoc(doc(db, 'entries', entry.id), { - is_synced: !entry.is_synced ?? true, - }); + return p; + }); + const isLiveClockingEntry = computed((): boolean => { + return !!entries.value.find((e) => e.is_live_clocking); + }); + const isCreatingEntry = computed((): boolean => { + return !!entries.value.find((e) => e.is_creating); + }); + const canCreateEntry = computed((): boolean => { + return !isLiveClockingEntry.value && !isCreatingEntry.value; + }); + + const weekSummaryColors = (time: string): string => { + const isZero = $moment.duration(time).asHours() === 0; + const isOvertime = $moment.duration(time).asHours() >= $moment.duration(weekObjective.value).asHours() / 5; + const isBelow = $moment.duration(time).asHours() >= $moment.duration(weekObjective.value).asHours() / 5 - 0.5; + + if (isZero) { + return 'text-gray-400 dark:text-gray-600'; + } else if (isOvertime) { + return 'text-green-500'; + } else if (isBelow) { + return 'text-yellow-500'; + } else { + return 'text-red-500'; } - async function addProject(option: Project) { - const project = await addDoc(collection(db, 'projects'), { - name: option.name, - user: user.value?.uid, - }); - return { id: project.id, name: option.name }; + }; + const projectEntriesTotal = (project: Project) => { + return entries.value.filter((e) => e?.project?.id === project.id).length; + }; + + async function addEntry(entry: Entry) { + await addDoc(collection(db, 'entries').withConverter(dateConverter), { + ...entry, + user: user.value?.uid, + project: doc(db, 'projects', entry.project.id), + }); + } + async function updateEntry(entry: Entry) { + await updateDoc(doc(db, 'entries', entry.id), { + ...entry, + project: doc(db, 'projects', entry.project.id), + date: $moment(entry.date).startOf('day').toDate(), + }); + } + async function deleteEntry(entry: Entry, force = false) { + if (force || confirm(t('Êtes vous certain de vouloir supprimer cette entrée ?'))) { + await deleteDoc(doc(db, 'entries', entry.id)); } - async function deleteProject(project: Project) { - if (confirm(t('Êtes vous certain de vouloir supprimer ce projet ?'))) { - const projectRef = doc(db, 'projects', project.id); - const { promise: linkedEntriesPromise } = await useCollection( - query(collection(db, 'entries'), where('project', '==', projectRef)), - { - once: true, - wait: true, - ssrKey: 'projectEntries', - }, - ); - const batch = writeBatch(db); - const linkedEntries = await linkedEntriesPromise.value; - if (linkedEntries.length > 0) { - if ( - confirm( - t( - "Cela entrainera la supression de l'entrée liée, êtes-vous certain de vouloir continuer ? | Cela entrainera la supression des {n} entrées liées, êtes-vous certain de vouloir continuer ?", - linkedEntries.length, - ), - ) - ) { - linkedEntries.forEach((entry) => { - batch.delete(doc(db, 'entries', entry.id)); - }); - await batch.commit(); - await deleteDoc(projectRef); - } - } else { + } + async function toggleEntrySynced(entry: Entry) { + await updateDoc(doc(db, 'entries', entry.id), { + is_synced: !entry.is_synced ?? true, + }); + } + async function addProject(option: Project) { + const project = await addDoc(collection(db, 'projects'), { + name: option.name, + user: user.value?.uid, + }); + return { id: project.id, name: option.name }; + } + async function deleteProject(project: Project) { + if (confirm(t('Êtes vous certain de vouloir supprimer ce projet ?'))) { + const projectRef = doc(db, 'projects', project.id); + const { promise: linkedEntriesPromise } = await useCollection( + query(collection(db, 'entries'), where('project', '==', projectRef)), + { + once: true, + wait: true, + ssrKey: 'projectEntries', + }, + ); + const batch = writeBatch(db); + const linkedEntries = await linkedEntriesPromise.value; + if (linkedEntries.length > 0) { + if ( + confirm( + t( + "Cela entrainera la supression de l'entrée liée, êtes-vous certain de vouloir continuer ? | Cela entrainera la supression des {n} entrées liées, êtes-vous certain de vouloir continuer ?", + linkedEntries.length, + ), + ) + ) { + linkedEntries.forEach((entry) => { + batch.delete(doc(db, 'entries', entry.id)); + }); + await batch.commit(); await deleteDoc(projectRef); } + } else { + await deleteDoc(projectRef); } } - async function addPriority(name: string) { - await addDoc(collection(db, 'priorities'), { - name, - completed: false, - user: user.value?.uid, - }); - } - async function deletePriority(priority: Priority, force = false) { - if (force || confirm(t('Êtes vous certain de vouloir supprimer cette priorité ?'))) { - await deleteDoc(doc(db, 'priorities', priority.id)); - } + } + async function addPriority(name: string) { + await addDoc(collection(db, 'priorities'), { + name, + completed: false, + user: user.value?.uid, + }); + } + async function deletePriority(priority: Priority, force = false) { + if (force || confirm(t('Êtes vous certain de vouloir supprimer cette priorité ?'))) { + await deleteDoc(doc(db, 'priorities', priority.id)); } - function deleteCompletedPriorities() { - const completed = priorities.value.filter((p: Priority) => p.completed); + } + function deleteCompletedPriorities() { + const completed = priorities.value.filter((p: Priority) => p.completed); - if (completed.length !== 0) { - if (confirm(t('Êtes vous certain de vouloir supprimer les priorités complétées ?'))) { - completed.forEach((p) => deletePriority(p, true)); - } - } else { - alert(t('Aucune priorité complétée à supprimer')); + if (completed.length !== 0) { + if (confirm(t('Êtes vous certain de vouloir supprimer les priorités complétées ?'))) { + completed.forEach((p) => deletePriority(p, true)); } + } else { + alert(t('Aucune priorité complétée à supprimer')); } + } - return { - // state - menuOpened, - selectedDay, - filter, - selectedTabIndex, - sort, - weekObjective, - projects, - entries, - priorities, - // getters - weekStart, - weekEnd, - todaysEntries, - weekTotal, - weekRemaining, - weekSummary, - weekSummaryColors, - weeklySummaryByProjects, - dailySummaryByProjects, - sortedProjects, - projectEntriesTotal, - isLiveClockingEntry, - isCreatingEntry, - canCreateEntry, - // actions - addEntry, - updateEntry, - deleteEntry, - toggleEntrySynced, - addProject, - deleteProject, - addPriority, - deletePriority, - deleteCompletedPriorities, - }; - }, - { - persist: { - paths: ['selectedDay', 'menuOpened', 'filter', 'selectedTabIndex', 'sort', 'weekObjective'], - }, - }, -); + return { + // state + menuOpened, + selectedDay, + filter, + selectedTabIndex, + sort, + weekObjective, + projects, + entries, + priorities, + // getters + weekStart, + weekEnd, + todaysEntries, + weekTotal, + weekRemaining, + weekSummary, + weekSummaryColors, + weeklySummaryByProjects, + dailySummaryByProjects, + sortedProjects, + projectEntriesTotal, + isLiveClockingEntry, + isCreatingEntry, + canCreateEntry, + // actions + addEntry, + updateEntry, + deleteEntry, + toggleEntrySynced, + addProject, + deleteProject, + addPriority, + deletePriority, + deleteCompletedPriorities, + }; +}); diff --git a/yarn.lock b/yarn.lock index a34109e..bcd9957 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1304,7 +1304,7 @@ which "^3.0.1" ws "^8.14.2" -"@nuxt/kit@3.7.4", "@nuxt/kit@^3.5.0", "@nuxt/kit@^3.5.3", "@nuxt/kit@^3.6.5", "@nuxt/kit@^3.7.1", "@nuxt/kit@^3.7.3", "@nuxt/kit@^3.7.4": +"@nuxt/kit@3.7.4", "@nuxt/kit@^3.5.0", "@nuxt/kit@^3.5.3", "@nuxt/kit@^3.6.5", "@nuxt/kit@^3.7.1", "@nuxt/kit@^3.7.4": version "3.7.4" resolved "https://registry.yarnpkg.com/@nuxt/kit/-/kit-3.7.4.tgz#31c0bd57397cc56a1098af5d6504353cc2e855a2" integrity sha512-/S5abZL62BITCvC/TY3KWA6N721U1Osln3cQdBb56XHIeafZCBVqTi92Xb0o7ovl72mMRhrKwRu7elzvz9oT/g== @@ -1592,15 +1592,6 @@ "@parcel/watcher-win32-ia32" "2.3.0" "@parcel/watcher-win32-x64" "2.3.0" -"@pinia-plugin-persistedstate/nuxt@^1.0.0": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@pinia-plugin-persistedstate/nuxt/-/nuxt-1.1.2.tgz#26a34fd0367516c3c7c17b8fbd237789ce99b393" - integrity sha512-3deRNiIlFoFGO/K8Sz+yc53ayMzElR8ack7RnGka80zBgp6Fs9GWjoLJiy+ToIc7qVa6wrQcoLDsxcnvzX4T0g== - dependencies: - "@nuxt/kit" "^3.7.3" - defu "^6.1.2" - pinia-plugin-persistedstate ">=3.2.0" - "@pinia/nuxt@^0.4.6": version "0.4.11" resolved "https://registry.yarnpkg.com/@pinia/nuxt/-/nuxt-0.4.11.tgz#1b3f728ae112d45deff5971376e05b8a8d64f720" @@ -5515,11 +5506,6 @@ pify@^2.3.0: resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== -pinia-plugin-persistedstate@>=3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-3.2.0.tgz#9932ca2ae88aa6c0d6763bebc6447d7bd1f097d0" - integrity sha512-tZbNGf2vjAQcIm7alK40sE51Qu/m9oWr+rEgNm/2AWr1huFxj72CjvpQcIQzMknDBJEkQznCLAGtJTIcLKrKdw== - pinia@>=2.1.0: version "2.1.6" resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.1.6.tgz#e88959f14b61c4debd9c42d0c9944e2875cbe0fa"