Merge branch 'main' of https://github.com/Byeto-Company/hossein_por_shop
This commit is contained in:
@@ -271,4 +271,40 @@
|
||||
button {
|
||||
@apply cursor-pointer;
|
||||
}
|
||||
|
||||
.vpd-main {
|
||||
@apply !w-full !border-none !p-0;
|
||||
}
|
||||
|
||||
.vpd-input-group {
|
||||
@apply !flex-row-reverse;
|
||||
}
|
||||
|
||||
.vpd-input-group > input {
|
||||
@apply !border-e-0 !rounded-none !rounded-s-100 !px-4;
|
||||
}
|
||||
|
||||
.vpd-input-group > label {
|
||||
@apply !rounded-e-100;
|
||||
}
|
||||
|
||||
.vpd-main > .vpd-wrapper > .vpd-container {
|
||||
@apply !rounded-xl !overflow-hidden;
|
||||
}
|
||||
|
||||
.vpd-main.error > .vpd-input-group > #vpd-vpd-date-picker {
|
||||
@apply border-danger-600 border-2;
|
||||
}
|
||||
|
||||
.vpd-main > .vpd-input-group > .vpd-icon-btn {
|
||||
@apply !bg-black;
|
||||
}
|
||||
|
||||
.vpd-main.error > .vpd-input-group > .vpd-icon-btn {
|
||||
@apply bg-danger-600 border-danger-600 border-t-2 border-r-2 border-b;
|
||||
}
|
||||
|
||||
.vpd-controls button {
|
||||
@apply flex justify-center items-center;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<script setup lang="ts">
|
||||
// imports
|
||||
|
||||
import DatePicker from "vue3-persian-datetime-picker";
|
||||
|
||||
// types
|
||||
|
||||
type Props = {
|
||||
modelValue: string;
|
||||
};
|
||||
|
||||
type Emits = {
|
||||
"update:modelValue": [value: string];
|
||||
};
|
||||
|
||||
// props
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const { modelValue } = toRefs(props);
|
||||
|
||||
// emit
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
// computed
|
||||
|
||||
const value = computed({
|
||||
get: () => modelValue.value ?? "",
|
||||
set: (value) => emit("update:modelValue", value),
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<DatePicker
|
||||
format="jYYYY-jMM-jDD"
|
||||
displayFormat="jYYYY-jMM-jDD"
|
||||
:editable="false"
|
||||
placeholder="وارد نشده"
|
||||
altFormat="jYYYY-jMM-jDD"
|
||||
color="#000000"
|
||||
inputClass="!py-3.5 placeholder-slate-400 rounded-e-100 !border-[1.5px] hover:!border-black !transition-all !border-slate-200 !text-sm"
|
||||
:autoSubmit="false"
|
||||
v-model="value"
|
||||
/>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
@@ -43,7 +43,7 @@ const isHomePage = computed(() => route.path === "/");
|
||||
? `${account.first_name.charAt(
|
||||
0
|
||||
)} ${account.last_name.charAt(0)}`
|
||||
: ''
|
||||
: 'بدون نام کاربری'
|
||||
"
|
||||
/>
|
||||
</NuxtLink>
|
||||
|
||||
@@ -5,15 +5,17 @@ type Props = {
|
||||
error?: boolean;
|
||||
message?: string;
|
||||
placeholder?: string;
|
||||
modelValue?: string;
|
||||
modelValue: string;
|
||||
};
|
||||
|
||||
// props
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
variant: "solid",
|
||||
disabled: false,
|
||||
placeholder: "وارد نشده",
|
||||
});
|
||||
const { variant, message, error, disabled } = toRefs(props);
|
||||
const { variant, message, error, disabled, modelValue } = toRefs(props);
|
||||
|
||||
// emits
|
||||
|
||||
@@ -25,6 +27,11 @@ const inputRef = ref<HTMLInputElement | null>(null);
|
||||
|
||||
// computed
|
||||
|
||||
const value = computed({
|
||||
get: () => modelValue.value ?? "",
|
||||
set: (value) => emit("update:modelValue", value),
|
||||
});
|
||||
|
||||
const classes = computed(() => {
|
||||
return [
|
||||
"flex items-center text-black justify-between cursor-text transition-all border-[1.5px] gap-3 typo-label-md px-4 py-3.5 selection:bg-slate-100 rounded-100",
|
||||
@@ -38,12 +45,6 @@ const classes = computed(() => {
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
// methods
|
||||
|
||||
const onInput = (e: any) => {
|
||||
emit("update:modelValue", e.target.value);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -51,8 +52,7 @@ const onInput = (e: any) => {
|
||||
<slot name="startItem" />
|
||||
|
||||
<input
|
||||
:value="modelValue"
|
||||
@input="onInput"
|
||||
v-model="value"
|
||||
ref="inputRef"
|
||||
class="outline-none flex-1 text-sm placeholder-slate-400"
|
||||
:placeholder="placeholder"
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
<script setup lang="ts">
|
||||
// types
|
||||
|
||||
type Props = {
|
||||
modelValue: boolean;
|
||||
icon?: string;
|
||||
title: string;
|
||||
iconSize?: string;
|
||||
};
|
||||
|
||||
type Emits = {
|
||||
"update:modelValue": [value: boolean];
|
||||
close: [value: null];
|
||||
};
|
||||
|
||||
// props
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const { modelValue } = toRefs(props);
|
||||
|
||||
// emit
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
// computed
|
||||
|
||||
const isShow = computed({
|
||||
get: () => modelValue.value ?? false,
|
||||
set: (value) => {
|
||||
emit("update:modelValue", value);
|
||||
emit("close", null);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogRoot v-model:open="isShow">
|
||||
<DialogTrigger>
|
||||
<slot name="trigger" />
|
||||
</DialogTrigger>
|
||||
<DialogPortal>
|
||||
<DialogOverlay
|
||||
class="bg-black/50 backdrop-blur-sm data-[state=open]:animate-overlay-show fixed inset-0 z-999"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="fixed inset-0 w-full h-svh z-9999 flex-center"
|
||||
v-if="isShow"
|
||||
>
|
||||
<div
|
||||
class="overflow-y-auto max-h-svh absolute left-[50%] py-10 w-fit max-w-[50rem] translate-x-[-50%]"
|
||||
>
|
||||
<DialogContent
|
||||
class="data-[state=open]:animate-content-show text-black font-iran-yekan-x focus:outline-none z-[100]"
|
||||
>
|
||||
<div
|
||||
class="rounded-3xl bg-white shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px]"
|
||||
>
|
||||
<div
|
||||
class="w-full flex items-center px-6 justify-between py-[1.5rem] border-b border-slate-200"
|
||||
>
|
||||
<DialogClose
|
||||
class="inline-flex size-8 items-center justify-center transition-all rounded-full bg-gray-50 border border-slate-200 hover:border-black focus:outline-none"
|
||||
aria-label="Close"
|
||||
>
|
||||
<Icon
|
||||
name="bi:x-lg"
|
||||
class="**:fill-black"
|
||||
/>
|
||||
</DialogClose>
|
||||
<DialogTitle
|
||||
class="typo-sub-h-xl font-semibold flex items-center gap-3"
|
||||
>
|
||||
{{ title }}
|
||||
<Icon
|
||||
v-if="!!icon"
|
||||
:name="icon"
|
||||
:size="iconSize"
|
||||
/>
|
||||
</DialogTitle>
|
||||
</div>
|
||||
<div class="w-full px-6">
|
||||
<slot name="content" />
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</div>
|
||||
</div>
|
||||
</DialogPortal>
|
||||
</DialogRoot>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -2,45 +2,63 @@
|
||||
// types
|
||||
|
||||
type Props = {
|
||||
variant?: "solid" | "outlined";
|
||||
disabled?: boolean;
|
||||
modelValue: string;
|
||||
error?: boolean;
|
||||
options: string[];
|
||||
placeholder: string;
|
||||
placeholder?: string;
|
||||
};
|
||||
|
||||
type Emit = {
|
||||
type Emits = {
|
||||
"update:modelValue": [value: string];
|
||||
};
|
||||
|
||||
// props
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
variant: "solid",
|
||||
disabled: false,
|
||||
placeholder: "وارد نشده",
|
||||
});
|
||||
|
||||
const { modelValue } = toRefs(props);
|
||||
const { modelValue, variant, error } = toRefs(props);
|
||||
|
||||
// emit
|
||||
|
||||
const emit = defineEmits<Emit>();
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
// state
|
||||
// computed
|
||||
|
||||
const selectedValue = computed({
|
||||
get: () => modelValue.value,
|
||||
get: () => modelValue.value ?? undefined,
|
||||
set: (value: string) => emit("update:modelValue", value),
|
||||
});
|
||||
|
||||
const classes = computed(() => {
|
||||
return [
|
||||
"flex items-center text-black justify-between cursor-text transition-all border-[1.5px] gap-3 typo-label-md px-4 py-3.5 selection:bg-slate-100 rounded-100 flex-1 w-full outline-none",
|
||||
{
|
||||
"input-solid": variant.value === "solid",
|
||||
"input-outlined": variant.value === "outlined",
|
||||
"input-effects": !error.value,
|
||||
[variant.value === "solid"
|
||||
? "input-solid-error"
|
||||
: "input-outlined-error"]: error.value,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
// watch
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectRoot v-model="selectedValue" dir="rtl">
|
||||
<SelectTrigger
|
||||
class="w-full flex items-center justify-between resize-none bg-slate-50 border-slate-200 hover:border-black focus:border-black h-[10rem] max-h-[12rem] text-black cursor-pointer transition-all border-[1.5px] gap-3 typo-label-md px-4 py-[12.5px] selection:bg-slate-100 rounded-100 outline-none flex-1 !text-sm placeholder-slate-400"
|
||||
aria-label="Customise options"
|
||||
>
|
||||
<SelectTrigger :class="classes" class="" aria-label="Customise options">
|
||||
<SelectValue
|
||||
:placeholder="placeholder"
|
||||
:class="selectedValue ? 'text-black' : 'text-slate-400'"
|
||||
class="font-iran-yekan-x"
|
||||
class="font-iran-yekan-x text-sm placeholder-slate-400"
|
||||
/>
|
||||
<Icon name="bi:chevron-down" size="16" />
|
||||
</SelectTrigger>
|
||||
|
||||
@@ -5,7 +5,7 @@ type Props = {
|
||||
modelValue: boolean;
|
||||
};
|
||||
|
||||
type Emit = {
|
||||
type Emits = {
|
||||
"update:modelValue": [value: boolean];
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ const { modelValue } = toRefs(props);
|
||||
|
||||
// emit
|
||||
|
||||
const emit = defineEmits<Emit>();
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
// computed
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
// types
|
||||
|
||||
type Props = {
|
||||
title: string;
|
||||
icon: string;
|
||||
};
|
||||
|
||||
// props
|
||||
|
||||
defineProps<Props>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center justify-between w-full gap-3 px-5 py-4 rounded-xl bg-slate-50 border border-slate-200"
|
||||
>
|
||||
<div class="flex items-center w-full gap-3 lg:w-1/2">
|
||||
<button class="flex-center lg:hidden">
|
||||
<Icon name="bi:chevron-right" size="24" class="**:fill-black" />
|
||||
</button>
|
||||
<p class="font-semibold lg:text-lg text-black">
|
||||
{{ title }}
|
||||
</p>
|
||||
</div>
|
||||
<Icon :name="icon" size="24" class="**:fill-black" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
// types
|
||||
|
||||
type Props = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
// props
|
||||
|
||||
defineProps<Props>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col w-full">
|
||||
<div class="flex flex-col items-start">
|
||||
<div class="w-full flex items-center p-5">
|
||||
<span class="typo-sub-h-lg">{{ title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full flex flex-col border border-slate-200 rounded-xl">
|
||||
<div class="w-full p-5">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -3,6 +3,33 @@
|
||||
|
||||
import useGetAccount from "~/composables/api/account/useGetAccount";
|
||||
|
||||
// state
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const profileLinks = ref([
|
||||
{
|
||||
icon: "bi:person-vcard",
|
||||
title: "پروفایل",
|
||||
path: { name: "profile" },
|
||||
},
|
||||
{
|
||||
icon: "bi:map",
|
||||
title: "آدرس ها",
|
||||
path: { name: "profile-addresses" },
|
||||
},
|
||||
{
|
||||
icon: "bi:cart",
|
||||
title: "خرید ها و سفارش ها",
|
||||
path: { name: "profile-purchases-and-orders" },
|
||||
},
|
||||
{
|
||||
icon: "bi:ticket",
|
||||
title: "تیکت ها",
|
||||
path: { name: "profile-tickets" },
|
||||
},
|
||||
]);
|
||||
|
||||
// queries
|
||||
|
||||
const { data: account, suspense } = useGetAccount();
|
||||
@@ -30,6 +57,31 @@ await suspense();
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="w-full flex flex-col gap-2 rounded-xl bg-slate-50 border border-slate-200 p-4"
|
||||
>
|
||||
<NuxtLink
|
||||
v-for="(link, index) in profileLinks"
|
||||
:key="index"
|
||||
:to="{ ...link.path }"
|
||||
:class="
|
||||
route.name == link.path.name
|
||||
? 'bg-black text-slate-100 **:fill-slate-100 '
|
||||
: '**:fill-black '
|
||||
"
|
||||
class="flex items-center justify-between transition-all rounded-lg py-4 px-3"
|
||||
>
|
||||
<span class="flex-center gap-3">
|
||||
<div class="size-5 flex-center">
|
||||
<Icon :name="link.icon" />
|
||||
</div>
|
||||
<span class="text-sm">{{ link.title }}</span>
|
||||
</span>
|
||||
|
||||
<Icon name="bi:chevron-left" class="transition-all" />
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
// types
|
||||
|
||||
type Props = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
// props
|
||||
|
||||
defineProps<Props>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center w-full lg:py-4 lg:border-b px-5 border-slate-200"
|
||||
>
|
||||
<p class="font-semibold lg:text-lg text-black">
|
||||
{{ title }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
// types
|
||||
|
||||
type Props = {
|
||||
id?: string;
|
||||
label: string;
|
||||
required?: boolean;
|
||||
error?: any;
|
||||
};
|
||||
|
||||
// props
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
required: false,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full flex flex-col gap-2">
|
||||
<div class="flex items-center gap-1 ps-2">
|
||||
<label :for="id" class="typo-label-sm">{{ label }}</label>
|
||||
<span v-if="required" class="text-danger-600">*</span>
|
||||
</div>
|
||||
<slot />
|
||||
<div
|
||||
class="w-full typo-label-xs flex items-center py-1 px-3 rounded-md text-danger-600"
|
||||
>
|
||||
این فیلد الزامی است
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,116 @@
|
||||
<script setup lang="ts">
|
||||
// state
|
||||
|
||||
const isShow = ref(false);
|
||||
|
||||
const currentProfile = ref("");
|
||||
|
||||
const avatars = ref([
|
||||
"/avatars/1.jpg",
|
||||
"/avatars/2.jpg",
|
||||
"/avatars/3.jpg",
|
||||
"/avatars/4.jpg",
|
||||
"/avatars/5.jpg",
|
||||
"/avatars/1.jpg",
|
||||
"/avatars/2.jpg",
|
||||
"/avatars/3.jpg",
|
||||
"/avatars/4.jpg",
|
||||
"/avatars/5.jpg",
|
||||
"/avatars/1.jpg",
|
||||
"/avatars/2.jpg",
|
||||
"/avatars/3.jpg",
|
||||
"/avatars/4.jpg",
|
||||
"/avatars/5.jpg",
|
||||
"/avatars/1.jpg",
|
||||
"/avatars/2.jpg",
|
||||
"/avatars/3.jpg",
|
||||
"/avatars/4.jpg",
|
||||
"/avatars/5.jpg",
|
||||
"/avatars/1.jpg",
|
||||
"/avatars/2.jpg",
|
||||
"/avatars/3.jpg",
|
||||
"/avatars/4.jpg",
|
||||
"/avatars/5.jpg",
|
||||
"/avatars/5.jpg",
|
||||
"/avatars/1.jpg",
|
||||
"/avatars/2.jpg",
|
||||
"/avatars/3.jpg",
|
||||
"/avatars/4.jpg",
|
||||
"/avatars/5.jpg",
|
||||
"/avatars/1.jpg",
|
||||
"/avatars/2.jpg",
|
||||
"/avatars/3.jpg",
|
||||
"/avatars/4.jpg",
|
||||
"/avatars/5.jpg",
|
||||
]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal v-model="isShow" title="عکس پروفایل" icon="bi:image" iconSize="20">
|
||||
<template #trigger>
|
||||
<button
|
||||
class="bg-black text-slate-100 rounded-full p-2 flex-center absolute -bottom-0 -right-0"
|
||||
>
|
||||
<Icon name="bi:pencil" class="**:fill-slate-100" size="12" />
|
||||
</button>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="w-max">
|
||||
<div
|
||||
class="w-full flex flex-col-reverse items-center justify-between py-10 gap-10 px-4"
|
||||
>
|
||||
<div
|
||||
class="flex items-center justify-between w-full flex-wrap gap-4 max-w-[500px]"
|
||||
>
|
||||
<button
|
||||
v-for="(avatar, index) in avatars"
|
||||
:key="index"
|
||||
class="size-20 rounded-full focus:ring-2 focus:ring-offset-1 focus:ring-black transition-all"
|
||||
>
|
||||
<Avatar
|
||||
:src="avatar"
|
||||
:alt="`avatar-${index}`"
|
||||
class="size-full"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="w-full flex-center gap-4 max-w-[500px] flex-wrap"
|
||||
>
|
||||
<button
|
||||
class="size-8 rounded-full bg-orange-100 whitespace-nowrap ring-2 hover:ring-black ring-slate-200 ring-offset-3"
|
||||
/>
|
||||
<button
|
||||
class="size-8 rounded-full bg-orange-200 whitespace-nowrap ring-2 hover:ring-black ring-slate-200 ring-offset-3"
|
||||
/>
|
||||
<button
|
||||
class="size-8 rounded-full bg-amber-600 whitespace-nowrap ring-2 hover:ring-black ring-slate-200 ring-offset-3"
|
||||
/>
|
||||
<button
|
||||
class="size-8 rounded-full bg-amber-700 whitespace-nowrap ring-2 hover:ring-black ring-slate-200 ring-offset-3"
|
||||
/>
|
||||
<button
|
||||
class="size-8 rounded-full bg-amber-800 whitespace-nowrap ring-2 hover:ring-black ring-slate-200 ring-offset-3"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="w-full flex-col-center gap-5">
|
||||
<div
|
||||
class="size-32 border border-slate-200 rounded-full"
|
||||
>
|
||||
<Avatar
|
||||
:src="currentProfile"
|
||||
:alt="''"
|
||||
class="size-full"
|
||||
/>
|
||||
</div>
|
||||
<Button class="rounded-full">آپلود عکس شما</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,4 +1,14 @@
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
// imports
|
||||
|
||||
import useGetAccount from "~/composables/api/account/useGetAccount";
|
||||
|
||||
// queries
|
||||
|
||||
const { suspense } = useGetAccount();
|
||||
|
||||
await suspense();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
@@ -7,7 +17,7 @@
|
||||
>
|
||||
<Header />
|
||||
<main
|
||||
class="w-full overflow-x-hidden container flex items-start gap-[5rem]"
|
||||
class="w-full overflow-x-hidden container flex items-start gap-[2rem]"
|
||||
>
|
||||
<ProfileSidebar />
|
||||
<div class="w-9/12">
|
||||
|
||||
Generated
+50
-1
@@ -29,7 +29,8 @@
|
||||
"vue": "latest",
|
||||
"vue-router": "latest",
|
||||
"vue-scrollto": "^2.20.0",
|
||||
"vue-skeletor": "^1.0.6"
|
||||
"vue-skeletor": "^1.0.6",
|
||||
"vue3-persian-datetime-picker": "^1.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/test-utils": "^3.15.4",
|
||||
@@ -7528,6 +7529,12 @@
|
||||
"@pkgjs/parseargs": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jalaali-js": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/jalaali-js/-/jalaali-js-1.2.7.tgz",
|
||||
"integrity": "sha512-gE+YHWSbygYAoJa+Xg8LWxGILqFOxZSBQQw39ghel01fVFUxV7bjL0x1JFsHcLQ3uPjvn81HQMa+kxwyPWnxGQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
|
||||
@@ -8520,6 +8527,39 @@
|
||||
"integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.30.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
||||
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/moment-jalaali": {
|
||||
"version": "0.9.6",
|
||||
"resolved": "https://registry.npmjs.org/moment-jalaali/-/moment-jalaali-0.9.6.tgz",
|
||||
"integrity": "sha512-v8wXjQplvk5ez+sUqgsWIrafwIf1BEXXvzTYwsg1wHcqh27nSgKPCJ6FnZRrCz03MoNyB9N31L0oms+vE8Rq7g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jalaali-js": "^1.1.0",
|
||||
"moment": "^2.22.2",
|
||||
"moment-timezone": "^0.5.21",
|
||||
"rimraf": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/moment-timezone": {
|
||||
"version": "0.5.47",
|
||||
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.47.tgz",
|
||||
"integrity": "sha512-UbNt/JAWS0m/NJOebR0QMRHBk0hu03r5dx9GK8Cs0AS3I81yDcOc9k+DytPItgVvBP7J6Mf6U2n3BPAacAV9oA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"moment": "^2.29.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/mri": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
|
||||
@@ -12704,6 +12744,15 @@
|
||||
"integrity": "sha512-ER4vHlFSXCW3ixK2DlczUE6CZliHsn4d2TvZ9/26C6Oq8zoyEY23BsqweMPtF8QULSz1+G5m2New1BwKNVOZhQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/vue3-persian-datetime-picker": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/vue3-persian-datetime-picker/-/vue3-persian-datetime-picker-1.2.2.tgz",
|
||||
"integrity": "sha512-d7nkj5vgtUvEXZboSdRmP1uwBfXvXgXqdvsOOMQb34jiMZU/aBDrTYWTEe1N+XKF9pvTTJn8Rws9ttJmyhK/hw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"moment-jalaali": "^0.9.4"
|
||||
}
|
||||
},
|
||||
"node_modules/w3c-xmlserializer": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
"vue": "latest",
|
||||
"vue-router": "latest",
|
||||
"vue-scrollto": "^2.20.0",
|
||||
"vue-skeletor": "^1.0.6"
|
||||
"vue-skeletor": "^1.0.6",
|
||||
"vue3-persian-datetime-picker": "^1.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/test-utils": "^3.15.4",
|
||||
|
||||
@@ -5,7 +5,7 @@ const contactInfo = ref({
|
||||
name: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
requestType: "",
|
||||
requestType: undefined,
|
||||
message: "",
|
||||
});
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
definePageMeta({
|
||||
middleware: "check-is-logged-in",
|
||||
layout: "profile",
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,14 +1,158 @@
|
||||
<script setup lang="ts">
|
||||
// imports
|
||||
|
||||
import useGetAccount from "~/composables/api/account/useGetAccount";
|
||||
|
||||
// meta
|
||||
|
||||
definePageMeta({
|
||||
middleware: "check-is-logged-in",
|
||||
layout: "profile",
|
||||
});
|
||||
|
||||
// state
|
||||
|
||||
const personalData = ref({
|
||||
name: "",
|
||||
last_name: "",
|
||||
phone: "",
|
||||
gender: undefined,
|
||||
email: "",
|
||||
birthDate: "",
|
||||
});
|
||||
|
||||
const alises = ref([
|
||||
"شکارچی",
|
||||
"آیفون باز",
|
||||
"خوش سلیقه",
|
||||
"دست و دلباز",
|
||||
"چرم باز",
|
||||
]);
|
||||
|
||||
// queries
|
||||
|
||||
const { data: account } = useGetAccount();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div></div>
|
||||
<div class="w-full flex flex-col gap-10">
|
||||
<ProfilePageTitle title="پروفایل" icon="bi:person-vcard" />
|
||||
|
||||
<div class="flex flex-col gap-6">
|
||||
<div
|
||||
class="w-full flex items-center justify-between border p-6 rounded-xl border-slate-200"
|
||||
>
|
||||
<div class="flex items-center justify-start gap-5 w-8/12">
|
||||
<div
|
||||
class="size-32 shrink-0 rounded-full border border-slate-200 flex-center relative"
|
||||
>
|
||||
<Avatar
|
||||
:src="account!.profile_photo"
|
||||
:alt="
|
||||
account?.first_name && account?.last_name
|
||||
? `${account?.first_name.charAt(
|
||||
0
|
||||
)} ${account?.last_name.charAt(0)}`
|
||||
: 'بدون نام کاربری'
|
||||
"
|
||||
/>
|
||||
|
||||
<PictureModal />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-3">
|
||||
<span class="typo-sub-h-lg"
|
||||
>{{ account?.first_name }}
|
||||
{{ account?.last_name }}</span
|
||||
>
|
||||
<span class="typo-sub-h-sm font-light text-slate-600">
|
||||
با اولین خریدتون هوش مصنوعی وبسایتمون واستون یک
|
||||
بایوگرافی درست میکنه :)
|
||||
</span>
|
||||
<span
|
||||
class="flex-center border border-yellow-500 pe-3.5 ps-1 w-max rounded-full"
|
||||
>
|
||||
<div class="rounded-full p-2">
|
||||
<Icon
|
||||
name="bi:patch-check"
|
||||
class="**:fill-yellow-400"
|
||||
size="20"
|
||||
/>
|
||||
</div>
|
||||
<span class="text-xs text-yellow-500"
|
||||
>جزو ۳ مشتری برتر</span
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-start gap-3 w-4/12">
|
||||
<span class="typo-sub-h-lg">لقب های شما</span>
|
||||
<span class="flex w-full flex-wrap gap-2">
|
||||
<span
|
||||
v-for="(alise, index) in alises"
|
||||
:key="index"
|
||||
class="flex-center bg-slate-50 border border-slate-200 py-2 px-3 w-max rounded-full"
|
||||
>
|
||||
<span class="text-xs text-black">{{ alise }}</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<ProfileSection title="اطلاعات شما">
|
||||
<div
|
||||
class="w-full grid grid-cols-1 lg:grid-cols-2 gap-x-3 gap-y-5"
|
||||
>
|
||||
<PersonalDataField id="personal-data-name" label="نام">
|
||||
<Input v-model="personalData.name" variant="outlined" />
|
||||
</PersonalDataField>
|
||||
<PersonalDataField
|
||||
id="personal-data-last-name"
|
||||
label="نام خانوادگی"
|
||||
>
|
||||
<Input
|
||||
v-model="personalData.last_name"
|
||||
variant="outlined"
|
||||
/>
|
||||
</PersonalDataField>
|
||||
<PersonalDataField id="personal-data-gender" label="جنسیت">
|
||||
<Select
|
||||
v-model="personalData.gender"
|
||||
:options="['مرد', 'زن']"
|
||||
variant="outlined"
|
||||
/>
|
||||
</PersonalDataField>
|
||||
<PersonalDataField
|
||||
id="personal-data-birth-date"
|
||||
label="تاریخ تولد"
|
||||
>
|
||||
<Datepicker v-model="personalData.birthDate" />
|
||||
</PersonalDataField>
|
||||
<PersonalDataField
|
||||
id="personal-data-phone"
|
||||
label="تلفن همراه"
|
||||
>
|
||||
<Input
|
||||
v-model="personalData.phone"
|
||||
variant="outlined"
|
||||
/>
|
||||
</PersonalDataField>
|
||||
<PersonalDataField
|
||||
id="personal-email"
|
||||
label="حساب الکترونیکی"
|
||||
>
|
||||
<Input
|
||||
v-model="personalData.email"
|
||||
variant="outlined"
|
||||
/>
|
||||
</PersonalDataField>
|
||||
</div>
|
||||
</ProfileSection>
|
||||
</div>
|
||||
<!-- <div class="w-fill grid grid-cols-1 lg:grid-cols-2">
|
||||
|
||||
</div> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
definePageMeta({
|
||||
middleware: "check-is-logged-in",
|
||||
layout: "profile",
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
definePageMeta({
|
||||
middleware: "check-is-logged-in",
|
||||
layout: "profile",
|
||||
});
|
||||
</script>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 97 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 120 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 730 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 809 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 984 KiB |
Reference in New Issue
Block a user