Skip to content

Commit

Permalink
Merge pull request #302 from letehaha/feat/improvements
Browse files Browse the repository at this point in the history
feat: Global UX improvements and fixes
  • Loading branch information
letehaha authored Aug 17, 2024
2 parents 191a88b + 288f017 commit 84cfc18
Show file tree
Hide file tree
Showing 18 changed files with 400 additions and 261 deletions.
2 changes: 1 addition & 1 deletion src/components/fields/form-wrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ defineProps<{
display: grid;
grid-gap: 8px;
animation: slide-appear 1s ease-out 300ms both;
// animation: slide-appear 1s ease-out 2000ms both;
}
.form-wrapper__error {
text-align: center;
Expand Down
19 changes: 19 additions & 0 deletions src/components/lib/ui/tooltip/Tooltip.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script setup lang="ts">
import {
TooltipRoot,
type TooltipRootEmits,
type TooltipRootProps,
useForwardPropsEmits,
} from "radix-vue";
const props = defineProps<TooltipRootProps>();
const emits = defineEmits<TooltipRootEmits>();
const forwarded = useForwardPropsEmits(props, emits);
</script>

<template>
<TooltipRoot v-bind="forwarded">
<slot />
</TooltipRoot>
</template>
50 changes: 50 additions & 0 deletions src/components/lib/ui/tooltip/TooltipContent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import {
TooltipContent,
type TooltipContentEmits,
type TooltipContentProps,
TooltipPortal,
useForwardPropsEmits,
} from "radix-vue";
import { cn } from "@/lib/utils";
defineOptions({
inheritAttrs: false,
});
const props = withDefaults(
defineProps<TooltipContentProps & { class?: HTMLAttributes["class"] }>(),
{
sideOffset: 4,
class: "",
},
);
const emits = defineEmits<TooltipContentEmits>();
const delegatedProps = computed(() => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { class: _, ...delegated } = props;
return delegated;
});
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>

<template>
<TooltipPortal>
<TooltipContent
v-bind="{ ...forwarded, ...$attrs }"
:class="
cn(
'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
props.class,
)
"
>
<slot />
</TooltipContent>
</TooltipPortal>
</template>
11 changes: 11 additions & 0 deletions src/components/lib/ui/tooltip/TooltipProvider.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script setup lang="ts">
import { TooltipProvider, type TooltipProviderProps } from "radix-vue";
const props = defineProps<TooltipProviderProps>();
</script>

<template>
<TooltipProvider v-bind="props">
<slot />
</TooltipProvider>
</template>
11 changes: 11 additions & 0 deletions src/components/lib/ui/tooltip/TooltipTrigger.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script setup lang="ts">
import { TooltipTrigger, type TooltipTriggerProps } from "radix-vue";
const props = defineProps<TooltipTriggerProps>();
</script>

<template>
<TooltipTrigger v-bind="props">
<slot />
</TooltipTrigger>
</template>
4 changes: 4 additions & 0 deletions src/components/lib/ui/tooltip/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { default as Tooltip } from "./Tooltip.vue";
export { default as TooltipContent } from "./TooltipContent.vue";
export { default as TooltipTrigger } from "./TooltipTrigger.vue";
export { default as TooltipProvider } from "./TooltipProvider.vue";
199 changes: 83 additions & 116 deletions src/components/modals/monobank-set-token.vue
Original file line number Diff line number Diff line change
@@ -1,170 +1,137 @@
<template>
<div class="monobank-set-token" data-cy="monobank-set-token-modal">
<ui-button
<Card
class="py-12 px-8 w-full max-w-[600px] relative rounded-xl"
data-cy="monobank-set-token-modal"
>
<Button
type="button"
class="button-style-reset monobank-set-token__close"
class="absolute top-3 right-3"
theme="light-dark"
is-icon
@click="$emit(MODAL_EVENTS.closeModal)"
>
X
</ui-button>
</Button>

<p class="monobank-set-token__descr">
<p class="my-5">
Please visit
<a href="https://api.monobank.ua/">https://api.monobank.ua/</a>
<a href="https://api.monobank.ua/" class="text-primary"
>https://api.monobank.ua/</a
>
and follow all the instructions. Paste the API token from Monobank in the
field below
</p>
<div class="monobank-set-token__row">
<div class="my-5">
<input-field
v-model="form.token"
name="token"
label="API Token"
:error-message="getFieldErrorMessage('form.token')"
/>
</div>
<div class="monobank-set-token__actions">
<ui-button
class="monobank-set-token__action monobank-set-token__action--submit"
type="submit"
:disabled="isLoading"
@click="submit"
>
<div class="flex justify-center">
<Button type="submit" :disabled="isLoading" @click="submit">
<template v-if="isUpdate"> Update token </template>
<template v-else> Pair account </template>
</ui-button>
</Button>
</div>
</div>
</Card>
</template>

<script lang="ts">
import { defineComponent, reactive, ref } from "vue";
<script setup lang="ts">
import { reactive, ref } from "vue";
import { API_ERROR_CODES } from "shared-types";
import { useBanksMonobankStore } from "@/stores";
import { useBanksMonobankStore, useCurrenciesStore } from "@/stores";
import { MONOBANK_API_TOKEN_LENGTH } from "@/common/const";
import { ApiErrorResponseError } from "@/js/errors";
import { useFormValidation } from "@/composable";
import { required, minLength } from "@/js/helpers/validators";
import InputField from "@/components/fields/input-field.vue";
import Button from "@/components/common/ui-button.vue";
import { EVENTS as MODAL_EVENTS } from "@/components/modal-center/ui-modal.vue";
import { Card } from "@/components/lib/ui/card";
import {
useNotificationCenter,
NotificationType,
} from "@/components/notification-center";
export default defineComponent({
defineOptions({
name: "monobank-set-token",
components: {
"input-field": InputField,
"ui-button": Button,
},
props: {
isUpdate: { type: Boolean, default: false },
});
const props = withDefaults(
defineProps<{
isUpdate?: boolean;
}>(),
{
isUpdate: false,
},
emits: [MODAL_EVENTS.closeModal],
setup(props, { emit }) {
const monobankStore = useBanksMonobankStore();
const { addNotification } = useNotificationCenter();
);
const isLoading = ref(false);
const form = reactive({ token: "" });
const { isFormValid, getFieldErrorMessage } = useFormValidation(
{ form },
{
form: {
token: {
required,
apiToken: minLength(MONOBANK_API_TOKEN_LENGTH),
},
},
},
undefined,
{
customValidationMessages: {
apiToken: `Monobank API token should be ${MONOBANK_API_TOKEN_LENGTH} characters length`,
},
const emit = defineEmits([MODAL_EVENTS.closeModal]);
const monobankStore = useBanksMonobankStore();
const currenciesStore = useCurrenciesStore();
const { addNotification } = useNotificationCenter();
const isLoading = ref(false);
const form = reactive({ token: "" });
const { isFormValid, getFieldErrorMessage } = useFormValidation(
{ form },
{
form: {
token: {
required,
apiToken: minLength(MONOBANK_API_TOKEN_LENGTH),
},
);
},
},
undefined,
{
customValidationMessages: {
apiToken: `Monobank API token should be ${MONOBANK_API_TOKEN_LENGTH} characters length`,
},
},
);
const submit = async () => {
try {
if (!isFormValid()) return;
const submit = async () => {
try {
if (!isFormValid()) return;
isLoading.value = true;
isLoading.value = true;
if (props.isUpdate) {
await monobankStore.updateUser({ token: form.token });
} else {
await monobankStore.pairAccount({ token: form.token });
}
if (props.isUpdate) {
await monobankStore.updateUser({ token: form.token });
} else {
await monobankStore.pairAccount({ token: form.token });
}
emit(MODAL_EVENTS.closeModal);
await currenciesStore.loadCurrencies();
addNotification({
text: "Paired",
type: NotificationType.success,
});
} catch (e) {
if (e instanceof ApiErrorResponseError) {
if (e.data.code === API_ERROR_CODES.monobankUserAlreadyConnected) {
addNotification({
text: "Account already connected",
type: NotificationType.error,
});
return;
}
}
emit(MODAL_EVENTS.closeModal);
addNotification({
text: "Paired",
type: NotificationType.success,
});
} catch (e) {
if (e instanceof ApiErrorResponseError) {
if (e.data.code === API_ERROR_CODES.monobankUserAlreadyConnected) {
addNotification({
text: "Unexpected error",
text: "Account already connected",
type: NotificationType.error,
});
} finally {
isLoading.value = false;
}
};
return {
MODAL_EVENTS,
form,
isLoading,
submit,
getFieldErrorMessage,
};
},
});
</script>

<style lang="scss" scoped>
.monobank-set-token {
background-color: var(--app-bg-box);
padding: 48px 32px;
width: 100%;
max-width: 600px;
position: relative;
border-radius: 12px;
}
.monobank-set-token__close {
position: absolute;
top: 12px;
right: 12px;
}
.monobank-set-token__row {
margin-bottom: 20px;
}
.monobank-set-token__actions {
display: flex;
justify-content: center;
}
.monobank-set-token__descr {
margin: 20px 0;
return;
}
}
a {
color: var(--app-primary);
addNotification({
text: "Unexpected error",
type: NotificationType.error,
});
} finally {
isLoading.value = false;
}
}
</style>
};
</script>
Loading

0 comments on commit 84cfc18

Please sign in to comment.