feat: switch language from profile

This commit is contained in:
Jannat Patel
2025-09-17 15:46:28 +05:30
parent 69f54a00c5
commit 90c53e4b46
6 changed files with 106 additions and 71 deletions

View File

@@ -2,7 +2,7 @@
<Dialog
:options="{
title: 'Edit your profile',
size: 'xl',
size: '3xl',
actions: [
{
label: 'Save',
@@ -13,74 +13,81 @@
}"
>
<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 class="grid grid-cols-2 gap-5">
<div class="space-y-4">
<!-- <Uploader
v-model="profile.image.file_url"
label="Profile Image"
description="Your profile image to help others recognize you."
/> -->
<div>
<div class="text-xs text-ink-gray-5 mb-1">
{{ __('Profile Image') }}
</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="flex items-center">
<img
:src="profile.image.file_url"
class="object-cover h-[50px] w-[50px] rounded-full border-4 border-white object-cover"
/>
<div class="text-base flex flex-col ml-2">
<span>
{{ profile.image.file_name }}
</span>
<span class="text-sm text-ink-gray-4 mt-1">
{{ getFileSize(profile.image.file_size) }}
</span>
</div>
<X
@click="removeImage()"
class="bg-surface-gray-3 rounded-md cursor-pointer stroke-1.5 w-5 h-5 p-1 ml-4"
/>
</div>
</div>
</template>
</FileUploader>
<div v-else class="mb-4">
<div class="text-xs text-ink-gray-5 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-ink-gray-7" />
<FormControl v-model="profile.first_name" :label="__('First Name')" />
<FormControl v-model="profile.last_name" :label="__('Last Name')" />
<FormControl v-model="profile.headline" :label="__('Headline')" />
<Link
:label="__('Language')"
v-model="profile.language"
doctype="Language"
/>
</div>
<div>
<div class="mb-4">
<div class="mb-1.5 text-sm text-ink-gray-5">
{{ __('Bio') }}
</div>
<div class="text-base flex flex-col">
<span>
{{ profile.image.file_name }}
</span>
<span class="text-sm text-ink-gray-4 mt-1">
{{ getFileSize(profile.image.file_size) }}
</span>
</div>
<X
@click="removeImage()"
class="bg-surface-gray-3 rounded-md cursor-pointer stroke-1.5 w-5 h-5 p-1 ml-4"
<TextEditor
:fixedMenu="true"
@change="(val) => (profile.bio = val)"
:content="profile.bio"
editorClass="prose-sm py-2 px-2 min-h-[200px] border-outline-gray-2 hover:border-outline-gray-3 rounded-b-md bg-surface-gray-3"
/>
</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"
/>
<div class="mb-4">
<div class="mb-1.5 text-sm text-ink-gray-5">
{{ __('Bio') }}
</div>
<TextEditor
:fixedMenu="true"
@change="(val) => (profile.bio = val)"
:content="profile.bio"
editorClass="prose-sm py-2 px-2 min-h-[200px] border-outline-gray-2 hover:border-outline-gray-3 rounded-md bg-surface-gray-3"
/>
</div>
</div>
</template>
</Dialog>
@@ -95,12 +102,14 @@ import {
TextEditor,
toast,
} from 'frappe-ui'
import { reactive, watch } from 'vue'
import { FileText, X } from 'lucide-vue-next'
import { ref, reactive, watch } from 'vue'
import { X } from 'lucide-vue-next'
import { getFileSize, decodeEntities } from '@/utils'
import Link from '@/components/Controls/Link.vue'
import DOMPurify from 'dompurify'
const reloadProfile = defineModel('reloadProfile')
const hasLanguageChanged = ref(false)
const props = defineProps({
profile: {
@@ -170,6 +179,10 @@ const saveProfile = (close) => {
onSuccess() {
close()
reloadProfile.value.reload()
if (hasLanguageChanged.value) {
hasLanguageChanged.value = false
window.location.reload()
}
},
onError(err) {
toast.error(err.messages?.[0] || err)
@@ -200,9 +213,19 @@ watch(
profile.first_name = newVal.first_name
profile.last_name = newVal.last_name
profile.headline = newVal.headline
profile.language = newVal.language
profile.bio = newVal.bio
if (newVal.user_image) imageResource.submit({ image: newVal.user_image })
}
}
)
watch(
() => profile.language,
(newVal, oldVal) => {
if (newVal !== oldVal) {
hasLanguageChanged.value = true
}
}
)
</script>

View File

@@ -30,9 +30,17 @@
</CodeEditor>
</div>
<div v-else-if="field.type == 'Upload'" class="space-y-2">
<div class="text-sm text-ink-gray-5 mb-1">
{{ __(field.label) }}
<div
v-else-if="field.type == 'Upload'"
class="grid grid-cols-2 gap-10"
>
<div class="space-y-2">
<div class="text-sm text-ink-gray-8 font-medium mb-1">
{{ __(field.label) }}
</div>
<div class="text-sm text-ink-gray-5 leading-5">
{{ __(field.description) }}
</div>
</div>
<FileUploader
v-if="!data[field.name]"

View File

@@ -267,11 +267,15 @@ const tabsStructure = computed(() => {
label: 'Logo',
name: 'banner_image',
type: 'Upload',
description:
'Appears in the top left corner of the application to represent your brand.',
},
{
label: 'Favicon',
name: 'favicon',
type: 'Upload',
description:
'Appears in the browser tab next to the page title, bookmarks, and shortcuts to help users quickly identify the application.',
},
],
},