Skip to content

Commit

Permalink
Put watched author methods in stats store
Browse files Browse the repository at this point in the history
Expose StarRating
  • Loading branch information
bperel committed Oct 21, 2023
1 parent b1db4bd commit dc87d40
Show file tree
Hide file tree
Showing 12 changed files with 192 additions and 130 deletions.
8 changes: 7 additions & 1 deletion apps/web/auto-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ declare global {
const h: typeof import('vue')['h']
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
const inject: typeof import('vue')['inject']
const injectLocal: typeof import('@vueuse/core')['injectLocal']
const isDefined: typeof import('@vueuse/core')['isDefined']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
Expand Down Expand Up @@ -75,6 +76,7 @@ declare global {
const onUpdated: typeof import('vue')['onUpdated']
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
const provide: typeof import('vue')['provide']
const provideLocal: typeof import('@vueuse/core')['provideLocal']
const reactify: typeof import('@vueuse/core')['reactify']
const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
const reactive: typeof import('vue')['reactive']
Expand Down Expand Up @@ -295,7 +297,7 @@ declare global {
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
}
// for vue template auto import
import { UnwrapRef } from 'vue'
Expand Down Expand Up @@ -342,6 +344,7 @@ declare module 'vue' {
readonly h: UnwrapRef<typeof import('vue')['h']>
readonly ignorableWatch: UnwrapRef<typeof import('@vueuse/core')['ignorableWatch']>
readonly inject: UnwrapRef<typeof import('vue')['inject']>
readonly injectLocal: UnwrapRef<typeof import('@vueuse/core')['injectLocal']>
readonly isDefined: UnwrapRef<typeof import('@vueuse/core')['isDefined']>
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
Expand Down Expand Up @@ -371,6 +374,7 @@ declare module 'vue' {
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']>
readonly provide: UnwrapRef<typeof import('vue')['provide']>
readonly provideLocal: UnwrapRef<typeof import('@vueuse/core')['provideLocal']>
readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']>
readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']>
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
Expand Down Expand Up @@ -632,6 +636,7 @@ declare module '@vue/runtime-core' {
readonly h: UnwrapRef<typeof import('vue')['h']>
readonly ignorableWatch: UnwrapRef<typeof import('@vueuse/core')['ignorableWatch']>
readonly inject: UnwrapRef<typeof import('vue')['inject']>
readonly injectLocal: UnwrapRef<typeof import('@vueuse/core')['injectLocal']>
readonly isDefined: UnwrapRef<typeof import('@vueuse/core')['isDefined']>
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
Expand Down Expand Up @@ -661,6 +666,7 @@ declare module '@vue/runtime-core' {
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']>
readonly provide: UnwrapRef<typeof import('vue')['provide']>
readonly provideLocal: UnwrapRef<typeof import('@vueuse/core')['provideLocal']>
readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']>
readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']>
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
Expand Down
7 changes: 7 additions & 0 deletions apps/web/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@ export {
createCachedUserApi,
getCommonCacheOptions,
} from "./src/api";
import StarRating from "./src/components/StarRating.vue";
import { bookcase } from "./src/stores/bookcase";
import { coa } from "./src/stores/coa";
import { collection } from "./src/stores/collection";
import { stats } from "./src/stores/stats";
export const stores = {
coa,
collection,
bookcase,
stats,
};

export const components = {
StarRating,
};

export { default as i18n } from "./src/i18n";
18 changes: 12 additions & 6 deletions apps/web/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,24 @@ import Cookies from "js-cookie";
import { coa } from "~/stores/coa";
import { collection } from "~/stores/collection";
import { stats } from "~/stores/stats";
import { addTokenRequestInterceptor } from "~axios-helper";
import { createCachedCoaApi } from "./api";
onBeforeMount(() => {
const defaultApi = addTokenRequestInterceptor(
axios.create({
baseURL: import.meta.env.VITE_GATEWAY_URL,
}),
() => Promise.resolve(Cookies.get("token") || ""),
);
stats().setApi({
api: defaultApi,
});
collection().setApi({
api: addTokenRequestInterceptor(
axios.create({
baseURL: import.meta.env.VITE_GATEWAY_URL,
}),
() => Promise.resolve(Cookies.get("token") || ""),
),
api: defaultApi,
clearSessionFn: () => Promise.resolve(Cookies.remove("token")),
sessionExistsFn: () =>
Promise.resolve(typeof Cookies.get("token") === "string"),
Expand Down
114 changes: 29 additions & 85 deletions apps/web/src/components/AuthorList.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div>
<b-alert
v-if="!watchedAuthors.length"
v-if="!ratings.length"
:model-value="true"
variant="warning"
class="section"
Expand Down Expand Up @@ -32,7 +32,7 @@
</p>
<div v-if="personNames">
<b-row
v-for="author in watchedAuthors"
v-for="author in ratings"
:key="author.personcode"
align-v="center"
class="mb-2"
Expand All @@ -43,12 +43,13 @@
<b-col lg="2">
<StarRating
v-model:rating="author.notation"
:readonly="false"
:max-rating="10"
@update:rating="updateRating(author)"
@update:rating="statsStore.updateRating(author)"
/>
</b-col>
<b-col lg="2">
<b-button size="sm" @click="deleteAuthor(author)">
<b-button size="sm" @click="statsStore.deleteAuthor(author)">
{{ $t("Supprimer") }}
</b-button>
</b-col>
Expand All @@ -57,11 +58,7 @@
</div>
<div>
<h5>{{ $t("Ajouter un auteur") }}</h5>
<b-alert
v-if="watchedAuthors.length >= 5"
variant="warning"
:model-value="true"
>
<b-alert v-if="ratings.length >= 5" variant="warning" :model-value="true">
{{
$t(
"Vous avez atteint le nombre maximal d'auteurs surveillés. Supprimez des auteurs existants pour en surveiller d'autres.",
Expand All @@ -79,7 +76,9 @@
/>
<datalist
v-if="
searchResults && Object.keys(searchResults) && !isSearching
searchResults &&
Object.keys(searchResults) &&
!statsStore.isSearching
"
>
<option v-if="!Object.keys(searchResults).length">
Expand All @@ -88,11 +87,13 @@
<option
v-for="(fullName, personcode) in searchResults"
:key="personcode"
:disabled="isAuthorWatched(personcode as string)"
:class="{
disabled: statsStore.isAuthorWatched(personcode as string),
}"
@click="
isAuthorWatched(personcode as string)
? () => {}
: createRating({ personcode: personcode as string })
statsStore.createRating({
personcode: personcode as string,
})
"
>
{{ fullName }}
Expand All @@ -107,99 +108,42 @@
</template>

<script setup lang="ts">
import axios from "axios";
import { watch } from "vue";
import { coa } from "~/stores/coa";
import { collection } from "~/stores/collection";
import {
DELETE__collection__authors__watched,
GET__coa__authorsfullnames__search__$partialAuthorName,
POST__collection__authors__watched,
PUT__collection__authors__watched,
} from "~api-routes";
import { call } from "~axios-helper";
import { inducks_person } from "~prisma-clients/client_coa";
import { stats } from "~/stores/stats";
import { authorUser } from "~prisma-clients/client_dm";
const { watchedAuthors } = defineProps<{
watchedAuthors: authorUser[];
const statsStore = stats();
const { ratings } = defineProps<{
ratings: authorUser[];
}>();
let isSearching = $ref(false as boolean);
let pendingSearch = $ref(null as string | null);
const search = $ref("");
let searchResults = $ref(
null as { [personcode: string]: inducks_person[] } | null,
);
const searchResults = $computed(() => statsStore.authorSearchResults);
const personNames = $computed(() => coa().personNames);
watch(
() => search,
async (newValue) => {
if (newValue !== "") {
pendingSearch = newValue;
if (!isSearching) await runSearch(newValue);
statsStore.pendingSearch = newValue;
if (!statsStore.isSearching) {
await statsStore.searchAuthors(newValue);
}
}
},
);
watch(
() => watchedAuthors,
() => ratings,
async (newValue) => {
if (watchedAuthors?.length) {
if (ratings?.length) {
await coa().fetchPersonNames(
newValue.map(({ personcode }) => personcode),
);
}
},
{ immediate: true },
);
const { loadWatchedAuthors } = collection();
const isAuthorWatched = (personcode: string) =>
watchedAuthors.some(
({ personcode: watchedPersonCode }) => personcode === watchedPersonCode,
);
const createRating = async (data: { personcode: string }) => {
await call(
axios,
new PUT__collection__authors__watched({
reqBody: data,
}),
);
await loadWatchedAuthors(true);
};
const updateRating = async (data: { personcode: string; notation: number }) => {
await call(axios, new POST__collection__authors__watched({ reqBody: data }));
};
const deleteAuthor = async (data: { personcode: string }) => {
await call(
axios,
new DELETE__collection__authors__watched({ reqBody: data }),
);
await loadWatchedAuthors(true);
};
const runSearch = async (value: string) => {
if (!isSearching) {
try {
isSearching = true;
searchResults = (
await call(
axios,
new GET__coa__authorsfullnames__search__$partialAuthorName({
params: {
partialAuthorName: value,
},
}),
)
).data;
} finally {
isSearching = false;
// The input value has changed since the beginning of the search, searching again
if (value !== pendingSearch) await runSearch(pendingSearch!);
}
}
};
</script>

<style scoped lang="scss">
Expand All @@ -226,8 +170,8 @@ datalist {
border-bottom: 1px solid #888;
overflow-x: hidden;
&[disabled] {
cursor: default;
&.disabled {
color: #777;
}
a {
Expand Down
24 changes: 18 additions & 6 deletions apps/web/src/components/StarRating.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div @mouseout="currentRating = rating">
<div :class="{ readonly }" @mouseout="currentRating = rating">
<span
v-for="index in maxRating"
:key="index"
Expand All @@ -12,24 +12,36 @@
</div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "StarRating",
});
</script>
<script setup lang="ts">
const { rating } = defineProps<{
rating: number;
maxRating: number;
readonly: boolean;
}>();
const emit = defineEmits<{
(e: "update:rating", currentRating: number): void;
}>();
const currentRating = $ref(rating);
const currentRating = ref(rating);
</script>

<style scoped lang="scss">
span {
cursor: pointer;
div {
&.readonly {
pointer-events: none;
}
span {
cursor: pointer;
svg {
fill: #ffc107;
svg {
fill: #ffc107;
}
}
}
</style>
3 changes: 2 additions & 1 deletion apps/web/src/pages/expand/suggestions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import { useI18n } from "vue-i18n";
import { coa } from "~/stores/coa";
import { collection as collectionStore } from "~/stores/collection";
import { stats as statsStore } from "~/stores/stats";
const countryCode = $ref("ALL" as string);
const { t: $t } = useI18n();
Expand Down Expand Up @@ -104,7 +105,7 @@ watch(
);
collectionStore().loadCollection();
collectionStore().loadWatchedAuthors();
statsStore().loadRatings();
</script>

<style scoped lang="scss">
Expand Down
Loading

0 comments on commit dc87d40

Please sign in to comment.