feat: profile page
This commit is contained in:
2
frontend/src/components/Modals/EditCoverImage.vue
Normal file
2
frontend/src/components/Modals/EditCoverImage.vue
Normal file
@@ -0,0 +1,2 @@
|
||||
<template></template>
|
||||
<script setup></script>
|
||||
178
frontend/src/components/Modals/EditProfile.vue
Normal file
178
frontend/src/components/Modals/EditProfile.vue
Normal file
@@ -0,0 +1,178 @@
|
||||
<template>
|
||||
<Dialog
|
||||
:options="{
|
||||
title: 'Edit your profile',
|
||||
size: 'xl',
|
||||
actions: [
|
||||
{
|
||||
label: 'Save',
|
||||
variant: 'solid',
|
||||
onClick: (close) => saveProfile(close),
|
||||
},
|
||||
],
|
||||
}"
|
||||
>
|
||||
<template #body-content>
|
||||
<div>
|
||||
<FileUploader
|
||||
v-if="!profile.image"
|
||||
:fileTypes="['image/*']"
|
||||
:validateFile="validateFile"
|
||||
@success="(file) => saveImage(file)"
|
||||
>
|
||||
<template v-slot="{ file, progress, uploading, openFileSelector }">
|
||||
<div class="mb-4">
|
||||
<Button @click="openFileSelector" :loading="uploading">
|
||||
{{
|
||||
uploading
|
||||
? `Uploading ${progress}%`
|
||||
: 'Upload a profile image'
|
||||
}}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</FileUploader>
|
||||
<div v-else class="mb-4">
|
||||
<div class="text-xs text-gray-600 mb-1">
|
||||
{{ __('Profile Image') }}
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class="border rounded-md p-2 mr-2">
|
||||
<FileText class="h-5 w-5 stroke-1.5 text-gray-700" />
|
||||
</div>
|
||||
<div class="text-base flex flex-col">
|
||||
<span>
|
||||
{{ profile.image.file_name }}
|
||||
</span>
|
||||
<span class="text-sm text-gray-500 mt-1">
|
||||
{{ getFileSize(profile.image.file_size) }}
|
||||
</span>
|
||||
</div>
|
||||
<X
|
||||
@click="removeImage()"
|
||||
class="bg-gray-200 rounded-md cursor-pointer stroke-1.5 w-5 h-5 p-1 ml-4"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<FormControl
|
||||
v-model="profile.first_name"
|
||||
:label="__('First Name')"
|
||||
class="mb-4"
|
||||
/>
|
||||
<FormControl
|
||||
v-model="profile.last_name"
|
||||
:label="__('Last Name')"
|
||||
class="mb-4"
|
||||
/>
|
||||
<FormControl
|
||||
v-model="profile.headline"
|
||||
:label="__('Headline')"
|
||||
class="mb-4"
|
||||
/>
|
||||
<FormControl type="textarea" v-model="profile.bio" :label="__('Bio')" />
|
||||
</div>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import {
|
||||
Dialog,
|
||||
FormControl,
|
||||
FileUploader,
|
||||
Button,
|
||||
createResource,
|
||||
} from 'frappe-ui'
|
||||
import { reactive, watch, defineModel } from 'vue'
|
||||
import { FileText, X } from 'lucide-vue-next'
|
||||
import { getFileSize, showToast } from '@/utils'
|
||||
|
||||
const reloadProfile = defineModel('reloadProfile')
|
||||
|
||||
const props = defineProps({
|
||||
profile: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const profile = reactive({
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
headline: '',
|
||||
bio: '',
|
||||
image: '',
|
||||
})
|
||||
|
||||
const imageResource = createResource({
|
||||
url: 'lms.lms.api.get_file_info',
|
||||
makeParams(values) {
|
||||
return {
|
||||
file_url: values.image,
|
||||
}
|
||||
},
|
||||
auto: false,
|
||||
onSuccess(data) {
|
||||
profile.image = data
|
||||
},
|
||||
})
|
||||
|
||||
const updateProfile = createResource({
|
||||
url: 'frappe.client.set_value',
|
||||
makeParams(values) {
|
||||
return {
|
||||
doctype: 'User',
|
||||
name: props.profile.data.name,
|
||||
fieldname: {
|
||||
user_image: profile.image.file_url,
|
||||
...profile,
|
||||
},
|
||||
}
|
||||
},
|
||||
onSuccess(data) {
|
||||
props.profile.data = data
|
||||
},
|
||||
})
|
||||
|
||||
const saveProfile = (close) => {
|
||||
updateProfile.submit(
|
||||
{},
|
||||
{
|
||||
onSuccess() {
|
||||
close()
|
||||
reloadProfile.value.reload()
|
||||
},
|
||||
onError(err) {
|
||||
showToast('Error', err.messages?.[0] || err, 'x')
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const validateFile = (file) => {
|
||||
let extension = file.name.split('.').pop().toLowerCase()
|
||||
if (!['jpg', 'jpeg', 'png'].includes(extension)) {
|
||||
return 'Only image file is allowed.'
|
||||
}
|
||||
}
|
||||
|
||||
const saveImage = (file) => {
|
||||
profile.image = file
|
||||
}
|
||||
|
||||
const removeImage = () => {
|
||||
profile.image = null
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.profile.data,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
profile.first_name = newVal.first_name
|
||||
profile.last_name = newVal.last_name
|
||||
profile.headline = newVal.headline
|
||||
profile.bio = newVal.bio
|
||||
if (newVal.user_image) imageResource.submit({ image: newVal.user_image })
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
@@ -46,7 +46,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="text-sm italic text-red-600">
|
||||
<div
|
||||
v-else-if="evaluation.course && evaluation.date"
|
||||
class="text-sm italic text-red-600"
|
||||
>
|
||||
{{ __('No slots available for this date.') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user