feat: encode search into url (#131)

* route query helper

* encode search parameters into url
This commit is contained in:
Hayden 2022-11-01 21:58:46 -08:00 committed by GitHub
parent b6b2a2d889
commit b7aacb3cde
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 135 additions and 12 deletions

View file

@ -0,0 +1,60 @@
/* eslint no-redeclare: 0 */
import { WritableComputedRef } from "vue";
export function useRouteQuery(q: string, def: string[]): WritableComputedRef<string[]>;
export function useRouteQuery(q: string, def: string): WritableComputedRef<string>;
export function useRouteQuery(q: string, def: boolean): WritableComputedRef<boolean>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function useRouteQuery(q: string, def: any): WritableComputedRef<any> {
const route = useRoute();
const router = useRouter();
switch (typeof def) {
case "string":
if (route.query[q] === undefined) {
router.push({ query: { ...route.query, [q]: def } });
}
return computed({
get: () => {
const qv = route.query[q];
if (Array.isArray(qv)) {
return qv[0];
}
return qv;
},
set: v => {
const query = { ...route.query, [q]: v };
router.push({ query });
},
});
case "object": // array
return computed({
get: () => {
const qv = route.query[q];
if (Array.isArray(qv)) {
return qv;
}
return [qv];
},
set: v => {
const query = { ...route.query, [q]: v };
router.push({ query });
},
});
case "boolean":
return computed({
get: () => {
const qv = route.query[q];
if (Array.isArray(qv)) {
return qv[0] === "true";
}
return qv === "true";
},
set: v => {
const query = { ...route.query, [q]: `${v}` };
router.push({ query });
},
});
}
}

View file

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ItemSummary } from "~~/lib/api/types/data-contracts"; import { watchPostEffect } from "vue";
import { ItemSummary, LabelSummary, LocationOutCount } from "~~/lib/api/types/data-contracts";
import { useLabelStore } from "~~/stores/labels"; import { useLabelStore } from "~~/stores/labels";
import { useLocationStore } from "~~/stores/locations"; import { useLocationStore } from "~~/stores/locations";
@ -11,13 +12,21 @@
title: "Homebox | Home", title: "Homebox | Home",
}); });
const api = useUserApi(); const searchLocked = ref(false);
const query = ref(""); const api = useUserApi();
const loading = useMinLoader(2000); const loading = useMinLoader(2000);
const results = ref<ItemSummary[]>([]); const results = ref<ItemSummary[]>([]);
const query = useRouteQuery("q", "");
const advanced = useRouteQuery("advanced", false);
const includeArchived = useRouteQuery("archived", false);
async function search() { async function search() {
if (searchLocked.value) {
return;
}
loading.value = true; loading.value = true;
const locations = selectedLocations.value.map(l => l.id); const locations = selectedLocations.value.map(l => l.id);
@ -38,8 +47,38 @@
loading.value = false; loading.value = false;
} }
onMounted(() => { const route = useRoute();
const router = useRouter();
const queryParamsInitialized = ref(false);
onMounted(async () => {
// Wait until locations and labels are loaded
let maxRetry = 10;
while (!labels.value || !locations.value) {
await new Promise(resolve => setTimeout(resolve, 100));
if (maxRetry-- < 0) {
break;
}
}
searchLocked.value = true;
const qLoc = route.query.loc as string[];
if (qLoc) {
selectedLocations.value = locations.value.filter(l => qLoc.includes(l.id));
}
const qLab = route.query.lab as string[];
if (qLab) {
selectedLabels.value = labels.value.filter(l => qLab.includes(l.id));
}
queryParamsInitialized.value = true;
searchLocked.value = false;
// trigger search if no changes
if (!qLab && !qLoc) {
search(); search();
}
}); });
const locationsStore = useLocationStore(); const locationsStore = useLocationStore();
@ -48,10 +87,36 @@
const labelStore = useLabelStore(); const labelStore = useLabelStore();
const labels = computed(() => labelStore.labels); const labels = computed(() => labelStore.labels);
const advanced = ref(false); const selectedLocations = ref<LocationOutCount[]>([]);
const selectedLocations = ref([]); const selectedLabels = ref<LabelSummary[]>([]);
const selectedLabels = ref([]);
const includeArchived = ref(false); watchPostEffect(() => {
if (!queryParamsInitialized.value) {
return;
}
const labelIds = selectedLabels.value.map(l => l.id);
router.push({
query: {
...router.currentRoute.value.query,
lab: labelIds,
},
});
});
watchPostEffect(() => {
if (!queryParamsInitialized.value) {
return;
}
const locIds = selectedLocations.value.map(l => l.id);
router.push({
query: {
...router.currentRoute.value.query,
loc: locIds,
},
});
});
watchEffect(() => { watchEffect(() => {
if (!advanced.value) { if (!advanced.value) {
@ -60,9 +125,7 @@
} }
}); });
watchDebounced(query, search, { debounce: 250, maxWait: 1000 }); watchDebounced([selectedLocations, selectedLabels, query], search, { debounce: 250, maxWait: 1000 });
watchDebounced(selectedLocations, search, { debounce: 250, maxWait: 1000 });
watchDebounced(selectedLabels, search, { debounce: 250, maxWait: 1000 });
watch(includeArchived, search); watch(includeArchived, search);
</script> </script>