feat: currency selection support (#72)

* initial UI for currency selection

* add task to purge invitation tokens

* group API contracts

* fix type import

* use auth middleware

* add currency setting support (UI)

* use group settings for format currency

* fix casing
This commit is contained in:
Hayden 2022-10-15 12:15:55 -08:00 committed by GitHub
parent 1cc38d6a5c
commit 461be2afca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 930 additions and 343 deletions

View file

@ -5,8 +5,9 @@
import { useLocationStore } from "~~/stores/locations";
definePageMeta({
layout: "home",
middleware: ["auth"],
});
useHead({
title: "Homebox | Home",
});
@ -15,15 +16,6 @@
const auth = useAuthStore();
if (auth.self === null) {
const { data, error } = await api.user.self();
if (error) {
navigateTo("/");
}
auth.$patch({ self: data.item });
}
const itemsStore = useItemStore();
const items = computed(() => itemsStore.items);

View file

@ -6,7 +6,7 @@
import { capitalize } from "~~/lib/strings";
definePageMeta({
layout: "home",
middleware: ["auth"],
});
const route = useRoute();

View file

@ -1,9 +1,9 @@
<script setup lang="ts">
import { DateDetail, Detail } from "~~/components/global/DetailsSection/types";
import { Detail, Details } from "~~/components/global/DetailsSection/types";
import { ItemAttachment } from "~~/lib/api/types/data-contracts";
definePageMeta({
layout: "home",
middleware: ["auth"],
});
const route = useRoute();
@ -145,7 +145,7 @@
});
const warrantyDetails = computed(() => {
const details: (Detail | DateDetail)[] = [
const details: Details = [
{
name: "Lifetime Warranty",
text: item.value?.lifetimeWarranty ? "Yes" : "No",
@ -180,7 +180,7 @@
return item.value?.purchaseFrom || item.value?.purchasePrice !== "0";
});
const purchaseDetails = computed<Array<Detail | DateDetail>>(() => {
const purchaseDetails = computed<Details>(() => {
return [
{
name: "Purchased From",
@ -188,7 +188,8 @@
},
{
name: "Purchase Price",
text: item.value?.purchasePrice ? fmtCurrency(item.value.purchasePrice) : "",
text: item.value?.purchasePrice || "",
type: "currency",
},
{
name: "Purchase Date",
@ -205,7 +206,7 @@
return item.value?.soldTo || item.value?.soldPrice !== "0";
});
const soldDetails = computed<Array<Detail | DateDetail>>(() => {
const soldDetails = computed<Details>(() => {
return [
{
name: "Sold To",
@ -213,7 +214,8 @@
},
{
name: "Sold Price",
text: item.value?.soldPrice ? fmtCurrency(item.value.soldPrice) : "",
text: item.value?.soldPrice || "",
type: "currency",
},
{
name: "Sold At",

View file

@ -1,6 +1,6 @@
<script setup>
definePageMeta({
layout: "home",
middleware: ["auth"],
});
const show = reactive({

View file

@ -4,8 +4,9 @@
import { useLocationStore } from "~~/stores/locations";
definePageMeta({
layout: "home",
middleware: ["auth"],
});
useHead({
title: "Homebox | Home",
});

View file

@ -1,8 +1,8 @@
<script setup lang="ts">
import type { DateDetail, Detail } from "~~/components/global/DetailsSection/types";
import type { CustomDetail, Detail } from "~~/components/global/DetailsSection/types";
definePageMeta({
layout: "home",
middleware: ["auth"],
});
const route = useRoute();
@ -23,7 +23,7 @@
return data;
});
const details = computed<(Detail | DateDetail)[]>(() => {
const details = computed<(Detail | CustomDetail)[]>(() => {
const details = [
{
name: "Name",

View file

@ -1,8 +1,8 @@
<script setup lang="ts">
import { Detail, DateDetail } from "~~/components/global/DetailsSection/types";
import { Detail, CustomDetail } from "~~/components/global/DetailsSection/types";
definePageMeta({
layout: "home",
middleware: ["auth"],
});
const route = useRoute();
@ -23,7 +23,7 @@
return data;
});
const details = computed<(Detail | DateDetail)[]>(() => {
const details = computed<(Detail | CustomDetail)[]>(() => {
const details = [
{
name: "Name",

View file

@ -1,15 +1,70 @@
<script setup lang="ts">
import { Detail } from "~~/components/global/DetailsSection/types";
import { DaisyTheme } from "~~/composables/use-preferences";
import { useAuthStore } from "~~/stores/auth";
import { themes } from "~~/lib/data/themes";
import { currencies, Currency } from "~~/lib/data/currency";
definePageMeta({
layout: "home",
middleware: ["auth"],
});
useHead({
title: "Homebox | Profile",
});
const api = useUserApi();
const confirm = useConfirm();
const notify = useNotifier();
// Currency Selection
const currency = ref<Currency>(currencies[0]);
watch(currency, () => {
if (group.value) {
group.value.currency = currency.value.code;
}
console.log(group.value);
});
const currencyExample = computed(() => {
const formatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: currency.value ? currency.value.code : "USD",
});
return formatter.format(1000);
});
const { data: group } = useAsyncData(async () => {
const { data } = await api.group.get();
return data;
});
// Sync Initial Currency
watch(group, () => {
if (group.value) {
const found = currencies.find(c => c.code === group.value.currency);
if (found) {
currency.value = found;
}
}
});
async function updateGroup() {
const { data, error } = await api.group.update({
name: group.value.name,
currency: group.value.currency,
});
if (error) {
notify.error("Failed to update group");
return;
}
group.value = data;
notify.success("Group updated");
}
const pubApi = usePublicApi();
const { data: status } = useAsyncData(async () => {
const { data } = await pubApi.status();
@ -19,126 +74,6 @@
const { setTheme } = useTheme();
type ThemeOption = {
label: string;
value: DaisyTheme;
};
const themes: ThemeOption[] = [
{
label: "Garden",
value: "garden",
},
{
label: "Light",
value: "light",
},
{
label: "Cupcake",
value: "cupcake",
},
{
label: "Bumblebee",
value: "bumblebee",
},
{
label: "Emerald",
value: "emerald",
},
{
label: "Corporate",
value: "corporate",
},
{
label: "Synthwave",
value: "synthwave",
},
{
label: "Retro",
value: "retro",
},
{
label: "Cyberpunk",
value: "cyberpunk",
},
{
label: "Valentine",
value: "valentine",
},
{
label: "Halloween",
value: "halloween",
},
{
label: "Forest",
value: "forest",
},
{
label: "Aqua",
value: "aqua",
},
{
label: "Lofi",
value: "lofi",
},
{
label: "Pastel",
value: "pastel",
},
{
label: "Fantasy",
value: "fantasy",
},
{
label: "Wireframe",
value: "wireframe",
},
{
label: "Black",
value: "black",
},
{
label: "Luxury",
value: "luxury",
},
{
label: "Dracula",
value: "dracula",
},
{
label: "Cmyk",
value: "cmyk",
},
{
label: "Autumn",
value: "autumn",
},
{
label: "Business",
value: "business",
},
{
label: "Acid",
value: "acid",
},
{
label: "Lemonade",
value: "lemonade",
},
{
label: "Night",
value: "night",
},
{
label: "Coffee",
value: "coffee",
},
{
label: "Winter",
value: "winter",
},
];
const auth = useAuthStore();
const details = computed(() => {
@ -154,10 +89,6 @@
] as Detail[];
});
const api = useUserApi();
const confirm = useConfirm();
const notify = useNotifier();
async function deleteProfile() {
const result = await confirm.open(
"Are you sure you want to delete your account? If you are the last member in your group all your data will be deleted. This action cannot be undone."
@ -283,6 +214,27 @@
</div>
</BaseCard>
<BaseCard>
<template #title>
<BaseSectionHeader class="pb-0">
<Icon name="mdi-accounts" class="mr-2 -mt-1 text-base-600" />
<span class="text-base-600"> Group Settings </span>
<template #description>
Shared Group Settings. You may need to refresh your browser for some settings to apply.
</template>
</BaseSectionHeader>
</template>
<div v-if="group" class="p-5 pt-0">
<FormSelect v-model="currency" value="code" label="Currency Format" :items="currencies" />
<p class="m-2 text-sm">Example: {{ currencyExample }}</p>
<div class="mt-4 flex justify-end">
<BaseButton @click="updateGroup"> Update Group </BaseButton>
</div>
</div>
</BaseCard>
<BaseCard>
<template #title>
<BaseSectionHeader>