Skip to content

Commit

Permalink
feat: Use shadcn's dialog for tx management modal
Browse files Browse the repository at this point in the history
  • Loading branch information
letehaha committed Sep 21, 2024
1 parent 90f9f8a commit 4d9ebdb
Show file tree
Hide file tree
Showing 28 changed files with 86 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ACCOUNT_TYPES,
TRANSACTION_TRANSFER_NATURE,
} from "shared-types";
import { DialogClose, DialogTitle } from "radix-vue";
import { useAccountsStore, useCategoriesStore, useCurrenciesStore } from "@/stores";
import {
createTransaction,
Expand All @@ -32,7 +33,6 @@ import CategorySelectField from "@/components/fields/category-select-field.vue";
import TextareaField from "@/components/fields/textarea-field.vue";
import DateField from "@/components/fields/date-field.vue";
import { Button } from "@/components/lib/ui/button";
import { EVENTS as MODAL_EVENTS } from "@/components/modal-center/ui-modal.vue";
import TransactionRecrod from "@/components/transactions-list/transaction-record.vue";
import { ApiErrorResponseError } from "@/js/errors";
import { useNotificationCenter } from "@/components/notification-center";
Expand All @@ -59,9 +59,9 @@ const props = withDefaults(defineProps<CreateRecordModalProps>(), {
oppositeTransaction: undefined,
});
const emit = defineEmits([MODAL_EVENTS.closeModal]);
const emit = defineEmits(["close-modal"]);
const closeModal = () => {
emit(MODAL_EVENTS.closeModal);
emit("close-modal");
};
const route = useRoute();
Expand Down Expand Up @@ -275,7 +275,7 @@ const submit = async () => {
);
}
emit(MODAL_EVENTS.closeModal);
closeModal();
// Reload all cached data in the app
queryClient.invalidateQueries({ queryKey: [VUE_QUERY_TX_CHANGE_QUERY] });
queryClient.invalidateQueries({
Expand All @@ -301,7 +301,7 @@ const unlinkTransactions = async () => {
transferIds: [props.transaction.transferId],
});
emit(MODAL_EVENTS.closeModal);
closeModal();
// Reload all cached data in the app
queryClient.invalidateQueries({ queryKey: [VUE_QUERY_TX_CHANGE_QUERY] });
} catch (err) {
Expand All @@ -320,7 +320,7 @@ const deleteTransactionHandler = async () => {
await deleteTransaction(props.transaction.id);
emit(MODAL_EVENTS.closeModal);
closeModal();
// Reload all cached data in the app
queryClient.invalidateQueries({ queryKey: [VUE_QUERY_TX_CHANGE_QUERY] });
} catch (e) {
Expand Down Expand Up @@ -363,7 +363,7 @@ onUnmounted(() => {
</script>

<template>
<div class="rounded-t-xl bg-card w-full max-w-[800px]">
<div class="rounded-t-xl">
<div
:class="[
'h-3 transition-[background-color] ease-out duration-200 rounded-t-xl',
Expand All @@ -373,11 +373,15 @@ onUnmounted(() => {
]"
/>
<div class="flex items-center justify-between py-3 px-6 mb-4">
<span class="text-2xl">
{{ isFormCreation ? "Add Transaction" : "Edit Transaction" }}
</span>

<Button variant="ghost" @click="closeModal"> Close </Button>
<DialogTitle>
<span class="text-2xl">
{{ isFormCreation ? "Add Transaction" : "Edit Transaction" }}
</span>
</DialogTitle>

<DialogClose>
<Button variant="ghost"> Close </Button>
</DialogClose>
</div>
<div class="grid grid-cols-[450px,1fr] relative">
<div class="px-6">
Expand Down Expand Up @@ -418,7 +422,7 @@ onUnmounted(() => {
:from-account-disabled="fromAccountFieldDisabled"
:to-account-disabled="toAccountFieldDisabled"
:filtered-accounts="transferDestinationAccounts"
@close-modal="emit(MODAL_EVENTS.closeModal)"
@close-modal="closeModal"
/>
<template v-if="currentTxType !== FORM_TYPES.transfer">
Expand Down
19 changes: 19 additions & 0 deletions src/components/dialogs/manage-transaction/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script setup lang="ts">
import { defineAsyncComponent, ref } from "vue";
import * as Dialog from "@/components/lib/ui/dialog";
const DialogContent = defineAsyncComponent(() => import("./dialog-content.vue"));
const isOpen = ref(false);
</script>

<template>
<Dialog.Dialog v-model:open="isOpen">
<Dialog.DialogTrigger as-child>
<slot />
</Dialog.DialogTrigger>
<Dialog.DialogContent custom-close class="max-h-[90dvh] w-full max-w-[800px] bg-card p-0">
<DialogContent @close-modal="isOpen = false" />
</Dialog.DialogContent>
</Dialog.Dialog>
</template>
18 changes: 11 additions & 7 deletions src/components/lib/ui/dialog/DialogContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import { Button } from "@/components/lib/ui/button";
import { X } from "lucide-vue-next";
import { cn } from "@/lib/utils";
const props = defineProps<DialogContentProps & { class?: HTMLAttributes["class"] }>();
const props = defineProps<
DialogContentProps & { class?: HTMLAttributes["class"]; customClose?: boolean }
>();
const emits = defineEmits<DialogContentEmits>();
const delegatedProps = computed(() => {
Expand Down Expand Up @@ -42,12 +44,14 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
>
<slot />

<DialogClose class="absolute right-4 top-4" as-child>
<Button variant="ghost" size="icon">
<X class="size-4" />
<span class="sr-only">Close</span>
</Button>
</DialogClose>
<template v-if="!customClose">
<DialogClose class="absolute right-4 top-4" as-child>
<Button variant="ghost" size="icon">
<X class="size-4" />
<span class="sr-only">Close</span>
</Button>
</DialogClose>
</template>
</DialogContent>
</DialogPortal>
</template>
15 changes: 2 additions & 13 deletions src/components/modal-center/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { ref, Ref } from "vue";
import { RecordListModalProps } from "@/components/modals/modify-record/record-list.vue";
import { CreateRecordModalProps } from "@/components/modals/modify-record/index.vue";
import { RecordListModalProps } from "@/components/dialogs/manage-transaction/record-list.vue";

export enum MODAL_TYPES {
createRecord = "createRecord",
recordList = "recordList",
monobankTxForm = "monobankTxForm",
monobankSetToken = "monobankSetToken",
}

interface CommonModalDataProps {
Expand All @@ -15,19 +11,12 @@ interface CommonModalDataProps {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data?: Record<string, any>;
}
interface CreateRecordModal extends CommonModalDataProps {
type: MODAL_TYPES.createRecord;
data?: CreateRecordModalProps;
}
interface MonobankTxFormModal extends CommonModalDataProps {
type: MODAL_TYPES.monobankTxForm;
}
interface RecordListModal extends CommonModalDataProps {
type: MODAL_TYPES.recordList;
data: RecordListModalProps;
}

export type ModalDataProp = RecordListModal | CreateRecordModal | MonobankTxFormModal;
export type ModalDataProp = RecordListModal;

let idCounter = 0;
const activeModals = ref<ModalDataProp[]>([]);
Expand Down
3 changes: 0 additions & 3 deletions src/components/modal-center/ui-modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ import { defineAsyncComponent, defineComponent, onBeforeUnmount } from "vue";
import { MODAL_TYPES, useModalCenter } from "./index";
const MODAL_COMPONENTS = Object.freeze({
[MODAL_TYPES.createRecord]: defineAsyncComponent(
() => import("@/components/modals/modify-record/index.vue"),
),
[MODAL_TYPES.recordList]: defineAsyncComponent(
() => import("@/components/modals/modify-record/record-list.vue"),
),
Expand Down
49 changes: 33 additions & 16 deletions src/components/transactions-list/transactions-list.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
<template>
<div class="transactions-list">
<template v-for="item in transactions" :key="`${item.id}-render-id-${renderId}`">
<TransactionRecrod :tx="item" @record-click="handlerRecordClick" />
</template>
</div>
<Dialog.Dialog v-model:open="isDialogVisible">
<div v-bind="$attrs" class="transactions-list">
<template v-for="item in transactions" :key="`${item.id}-render-id-${renderId}`">
<TransactionRecrod :tx="item" @record-click="handlerRecordClick" />
</template>
</div>

<Dialog.DialogContent custom-close class="max-h-[90dvh] w-full max-w-[800px] bg-card p-0">
<ManageTransactionDoalogContent v-bind="dialogProps" />
</Dialog.DialogContent>
</Dialog.Dialog>
</template>

<script lang="ts" setup>
import { ref, watch } from "vue";
import { defineAsyncComponent, ref, watch } from "vue";
import {
TransactionModel,
ACCOUNT_TYPES,
TRANSACTION_TYPES,
TRANSACTION_TRANSFER_NATURE,
} from "shared-types";
import { MODAL_TYPES, useModalCenter } from "@/components/modal-center/index";
import * as Dialog from "@/components/lib/ui/dialog";
import TransactionRecrod from "./transaction-record.vue";
const ManageTransactionDoalogContent = defineAsyncComponent(
() => import("@/components/dialogs/manage-transaction/dialog-content.vue"),
);
const props = withDefaults(
defineProps<{
transactions: TransactionModel[];
Expand All @@ -27,7 +37,19 @@ const props = withDefaults(
},
);
const { addModal } = useModalCenter();
const isDialogVisible = ref(false);
const defaultDialogProps = {
transaction: undefined,
oppositeTransaction: undefined,
};
const dialogProps = ref<{
transaction: TransactionModel;
oppositeTransaction: TransactionModel;
}>(defaultDialogProps);
watch(isDialogVisible, (value) => {
if (value === false) dialogProps.value = defaultDialogProps;
});
const handlerRecordClick = ([baseTx, oppositeTx]: [
baseTx: TransactionModel,
Expand All @@ -37,10 +59,7 @@ const handlerRecordClick = ([baseTx, oppositeTx]: [
baseTx.accountType !== ACCOUNT_TYPES.system ||
(oppositeTx && oppositeTx.accountType !== ACCOUNT_TYPES.system);
const modalOptions: {
transaction: TransactionModel;
oppositeTransaction?: TransactionModel;
} = {
const modalOptions: typeof dialogProps.value = {
transaction: baseTx,
oppositeTransaction: undefined,
};
Expand All @@ -60,10 +79,8 @@ const handlerRecordClick = ([baseTx, oppositeTx]: [
modalOptions.oppositeTransaction = isValid ? oppositeTx : baseTx;
}
addModal({
type: MODAL_TYPES.createRecord,
data: modalOptions,
});
isDialogVisible.value = true;
dialogProps.value = modalOptions;
};
// Since transactions list might change inside but txId will remain the same
Expand Down
10 changes: 4 additions & 6 deletions src/components/ui-header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
<div class="layout-header">
<div class="layout-header__actions">
<div class="layout-header__action">
<ui-button variant="default" size="lg" @click="openFormModal"> New Transaction </ui-button>
<ManageTransactionDialog>
<ui-button variant="default" size="lg"> New Transaction </ui-button>
</ManageTransactionDialog>
</div>
</div>

Expand Down Expand Up @@ -46,22 +48,18 @@
import { computed } from "vue";
import { storeToRefs } from "pinia";
import { useRootStore } from "@/stores";
import { MODAL_TYPES, useModalCenter } from "@/components/modal-center/index";
import UiTooltip from "@/components/common/tooltip.vue";
import { toggleTheme, currentTheme, Themes } from "@/common/utils";
import UiButton from "@/components/lib/ui/button/Button.vue";
import { MoonStar, Sun, CheckCircle, RefreshCcw } from "lucide-vue-next";
import ManageTransactionDialog from "@/components/dialogs/manage-transaction/index.vue";
const { addModal } = useModalCenter();
const rootStore = useRootStore();
const { isAppInitialized, isFinancialDataSyncing, isAllowedToSyncFinancialData } =
storeToRefs(rootStore);
const isSyncing = computed(() => !isAppInitialized.value || isFinancialDataSyncing.value);
const openFormModal = () => {
addModal({ type: MODAL_TYPES.createRecord });
};
const syncFinancialDataHandler = () => {
if (isAllowedToSyncFinancialData.value) {
rootStore.syncFinancialData();
Expand Down

0 comments on commit 4d9ebdb

Please sign in to comment.