init git
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
<template>
|
||||
<NuxtLayout :name="device" :config="config">
|
||||
<main class="user-profile-edit">
|
||||
<div>
|
||||
<h1>{{ $t("userProfileEdit") }}</h1>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<img :src="image" />
|
||||
<input ref="input" type="file" hidden @change="chooseImage" />
|
||||
<Button v-bind="btns.upload.props" @click="showImages()" />
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<ul>
|
||||
<li v-for="(item, key) in fields" :key="key">
|
||||
<component :id="key" :is="item.is" v-bind="item.props" v-model="form[key]" />
|
||||
<label :for="key"> {{ $t(key) }} </label>
|
||||
<small v-if="errors[key]">{{ errors[key] }}</small>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<Button v-bind="btns.form.cancel.props" @click="$router.go(-1)" />
|
||||
<Button v-bind="btns.form.save.props" :loading="loading" @click="save()" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import iranCities from "../../initialize/iranCities"
|
||||
import init from "../../initialize/userProfileEdit";
|
||||
const { device, toast, t } = inject('service')
|
||||
const config = reactive({
|
||||
mobile: { header: { title: t('edit') } }
|
||||
})
|
||||
const { btns, fields } = init();
|
||||
const source = ref();
|
||||
const image = ref();
|
||||
const input = ref();
|
||||
const form = reactive({});
|
||||
const errors = ref({});
|
||||
const loading = ref(false);
|
||||
const router = useRouter();
|
||||
|
||||
const { status, data, error } = await useFetch('/api/users/current', {
|
||||
headers: {
|
||||
Authorization: useCookie('token')
|
||||
},
|
||||
})
|
||||
|
||||
const provinces = reactive(iranCities)
|
||||
fields.state.props.options = provinces
|
||||
|
||||
watch(() => form.state, (v) => {
|
||||
provinces.forEach(({ name, cities }) => {
|
||||
if (name == v) {
|
||||
fields.city.props.options = reactive(cities)
|
||||
}
|
||||
});
|
||||
}, { deep: true })
|
||||
|
||||
fields.city.props.disabled = computed(() => fields.city.props.options.length < 1)
|
||||
|
||||
if (status.value == 'success') {
|
||||
Object.keys(fields).forEach(key => {
|
||||
form[key] = data.value[key]
|
||||
});
|
||||
image.value = data.value.profilePhoto ?? '/images/empty-profile.svg'
|
||||
}
|
||||
else throw createError(error.value)
|
||||
|
||||
const showImages = () => input.value.click()
|
||||
|
||||
const chooseImage = (e) => {
|
||||
const binaryData = [];
|
||||
binaryData.push(e.target.files[0]);
|
||||
image.value = URL.createObjectURL(new Blob(binaryData, { type: "image" }))
|
||||
source.value = e.target.files[0];
|
||||
}
|
||||
|
||||
const save = async () => {
|
||||
errors.value = {}
|
||||
loading.value = true
|
||||
if (source.value) {
|
||||
const formData = new FormData()
|
||||
formData.append('images', source.value)
|
||||
const { status, data, error } = await useFetch('/api/images/upload', {
|
||||
headers: { Authorization: useCookie('token') },
|
||||
params: { type: 3 },
|
||||
body: formData,
|
||||
method: 'post'
|
||||
})
|
||||
if (status.value == "success") {
|
||||
form.profilePhoto = data.value.urls[0]
|
||||
}
|
||||
}
|
||||
|
||||
const { status, data, error } = await useFetch('/api/users/', {
|
||||
headers: { Authorization: useCookie('token') }, body: Object.assign({}, form), method: 'patch'
|
||||
})
|
||||
|
||||
if (status.value == "success") {
|
||||
router.go(-1)
|
||||
toast.add({
|
||||
life: 5000, severity: 'success', summary: t('success'), detail: t('updateSuccessfull')
|
||||
})
|
||||
} else {
|
||||
if (error.value.statusCode == 422)
|
||||
errors.value = error.value.data
|
||||
else
|
||||
toast.add({
|
||||
life: 5000,
|
||||
severity: 'error',
|
||||
summary: t('error'),
|
||||
detail: error.value.data.message || error.value.message
|
||||
})
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.user-profile-edit {
|
||||
@apply w-full flex flex-col gap-[5.5rem] mb-[8.8rem];
|
||||
|
||||
&>div:nth-of-type(1) {
|
||||
@apply h-[5.9rem] bg-[#F2F2F2] flex items-center justify-center;
|
||||
|
||||
h1 {
|
||||
@apply text-[#333333] text-2xl font-bold font-iran-sans;
|
||||
}
|
||||
}
|
||||
|
||||
&>div:nth-of-type(2) {
|
||||
@apply flex gap-20 justify-center self-center flex-col md:flex-row w-full sm:w-auto px-4;
|
||||
|
||||
&>div:nth-of-type(1) {
|
||||
@apply flex flex-col gap-6 self-center md:self-start;
|
||||
|
||||
img {
|
||||
@apply w-[12.4rem] h-[12.4rem] rounded-[0.6rem];
|
||||
}
|
||||
|
||||
button {
|
||||
@apply w-[12.4rem] h-12 p-0 justify-center #{!important};
|
||||
|
||||
.p-button-label {
|
||||
@apply text-sm font-medium font-iran-sans grow-0;
|
||||
}
|
||||
|
||||
.p-button-icon {
|
||||
@apply text-xl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&>div:nth-of-type(2) {
|
||||
@apply overflow-y-hidden h-max -mt-4 flex flex-col gap-14;
|
||||
|
||||
&>div:nth-of-type(1) {
|
||||
@apply md:overflow-y-auto md:max-h-[40rem] w-full;
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
@apply bg-transparent my-4;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply flex flex-col gap-6 w-full max-w-full md:pl-7 md:py-4 my-0 pr-px;
|
||||
|
||||
li {
|
||||
@apply w-full sm:w-[27.1rem] h-14 relative col-span-2;
|
||||
|
||||
label {
|
||||
@apply w-max absolute right-3 top-4 px-1 bg-white transition-['top'] select-none;
|
||||
@apply text-neutral-400 text-base font-medium font-vazir cursor-text pointer-events-none;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
@apply rtl w-full rounded-[0.6rem] border shadow-none border-[#CCCCCC] text-zinc-800 font-vazir;
|
||||
}
|
||||
|
||||
input[type] {
|
||||
@apply ltr;
|
||||
}
|
||||
|
||||
&:has(input:focus),
|
||||
&:has(textarea:focus),
|
||||
&:has(.p-inputwrapper-filled),
|
||||
&:has(input:not(:placeholder-shown)),
|
||||
&:has(textarea:not(:placeholder-shown)) {
|
||||
label {
|
||||
@apply -top-2 h-4;
|
||||
@apply text-zinc-800 text-xs font-normal font-vazir;
|
||||
}
|
||||
}
|
||||
|
||||
.p-inputnumber,
|
||||
.p-dropdown,
|
||||
.p-calendar {
|
||||
@apply w-full;
|
||||
|
||||
}
|
||||
|
||||
.p-dropdown .p-dropdown-label {
|
||||
@apply font-vazir leading-7;
|
||||
}
|
||||
|
||||
.p-calendar {
|
||||
@apply flex items-center relative z-0 gap-4 font-['iconsax'] #{!important};
|
||||
|
||||
&::before {
|
||||
@apply text-xl absolute left-3 z-[1] mb-1;
|
||||
}
|
||||
|
||||
input {
|
||||
@apply pl-10 #{!important};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
.p-inputnumber input {
|
||||
@apply ltr;
|
||||
}
|
||||
|
||||
small {
|
||||
@apply text-red-500 font-vazir float-left;
|
||||
}
|
||||
|
||||
&:has(small) * {
|
||||
@apply border-red-500 #{!important};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&>div:nth-of-type(2) {
|
||||
@apply flex flex-wrap gap-3;
|
||||
|
||||
&>button {
|
||||
@apply w-full sm:w-[13.2rem] h-12;
|
||||
|
||||
.p-button-label {
|
||||
@apply text-sm font-medium font-iran-sans;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user