refactor: general settings

(cherry picked from commit c7fbd6f8f15b73fa2d69065eac32a014fef2596c)
This commit is contained in:
Shariq Ansari 2025-07-10 15:27:55 +05:30 committed by Mergify
parent 69780ecbd9
commit f733ef2fe7
6 changed files with 182 additions and 42 deletions

View File

@ -31,6 +31,7 @@ declare module 'vue' {
Autocomplete: typeof import('./src/components/frappe-ui/Autocomplete.vue')['default']
AvatarIcon: typeof import('./src/components/Icons/AvatarIcon.vue')['default']
BrandLogo: typeof import('./src/components/BrandLogo.vue')['default']
BrandSettings: typeof import('./src/components/Settings/General/BrandSettings.vue')['default']
BulkDeleteLinkedDocModal: typeof import('./src/components/BulkDeleteLinkedDocModal.vue')['default']
CalendarIcon: typeof import('./src/components/Icons/CalendarIcon.vue')['default']
CallArea: typeof import('./src/components/Activities/CallArea.vue')['default']
@ -127,7 +128,8 @@ declare module 'vue' {
FormattedInput: typeof import('./src/components/Controls/FormattedInput.vue')['default']
FrappeCloudIcon: typeof import('./src/components/Icons/FrappeCloudIcon.vue')['default']
GenderIcon: typeof import('./src/components/Icons/GenderIcon.vue')['default']
GeneralSettings: typeof import('./src/components/Settings/GeneralSettings.vue')['default']
GeneralSettings: typeof import('./src/components/Settings/General/GeneralSettings.vue')['default']
GeneralSettingsPage: typeof import('./src/components/Settings/General/GeneralSettingsPage.vue')['default']
GlobalModals: typeof import('./src/components/Modals/GlobalModals.vue')['default']
GoogleIcon: typeof import('./src/components/Icons/GoogleIcon.vue')['default']
Grid: typeof import('./src/components/Controls/Grid.vue')['default']
@ -138,6 +140,7 @@ declare module 'vue' {
GroupByIcon: typeof import('./src/components/Icons/GroupByIcon.vue')['default']
HeartIcon: typeof import('./src/components/Icons/HeartIcon.vue')['default']
HelpIcon: typeof import('./src/components/Icons/HelpIcon.vue')['default']
HomeActions: typeof import('./src/components/Settings/General/HomeActions.vue')['default']
Icon: typeof import('./src/components/Icon.vue')['default']
IconPicker: typeof import('./src/components/IconPicker.vue')['default']
ImageUploader: typeof import('./src/components/Controls/ImageUploader.vue')['default']

View File

@ -1,31 +1,37 @@
<template>
<div class="flex h-full flex-col gap-6 p-8 text-ink-gray-8">
<div class="flex justify-between">
<div class="flex flex-col gap-1 w-9/12">
<h2 class="flex gap-2 text-xl font-semibold leading-none h-5">
{{ __('General') }}
<Badge
v-if="settings.isDirty"
:label="__('Not Saved')"
variant="subtle"
theme="orange"
/>
</h2>
<p class="text-p-base text-ink-gray-6">
{{ __('Configure general settings for your CRM') }}
</p>
<div class="flex h-full flex-col gap-6 px-6 py-8 text-ink-gray-8">
<!-- Header -->
<div class="flex px-2 justify-between">
<div class="flex items-center gap-1 -ml-4 w-9/12">
<Button
variant="ghost"
icon-left="chevron-left"
:label="__('Brand settings')"
size="md"
@click="() => emit('updateStep', 'general-settings')"
class="text-xl !h-7 font-semibold hover:bg-transparent focus:bg-transparent focus:outline-none focus:ring-0 focus:ring-offset-0 focus-visible:none active:bg-transparent active:outline-none active:ring-0 active:ring-offset-0 active:text-ink-gray-5"
/>
<Badge
v-if="settings.isDirty"
:label="__('Not Saved')"
variant="subtle"
theme="orange"
/>
</div>
<div class="flex item-center space-x-2 w-3/12 justify-end">
<Button
variant="solid"
:label="__('Update')"
icon-left="plus"
variant="solid"
:disabled="!settings.isDirty"
:loading="settings.loading"
@click="updateSettings"
/>
</div>
</div>
<div v-if="settings.doc" class="flex-1 flex flex-col gap-8 overflow-y-auto">
<!-- Fields -->
<div class="flex flex-1 flex-col p-2 gap-4 overflow-y-auto">
<div class="flex w-full">
<FormControl
type="text"
@ -36,7 +42,6 @@
</div>
<!-- logo -->
<div class="flex flex-col justify-between gap-4">
<span class="text-base font-semibold text-ink-gray-8">
{{ __('Logo') }}
@ -71,7 +76,6 @@
</div>
<!-- favicon -->
<div class="flex flex-col justify-between gap-4">
<span class="text-base font-semibold text-ink-gray-8">
{{ __('Favicon') }}
@ -104,33 +108,18 @@
</div>
</div>
</div>
<!-- Home actions -->
<div class="flex flex-col justify-between gap-4">
<span class="text-base font-semibold text-ink-gray-8">
{{ __('Home actions') }}
</span>
<div class="flex flex-1">
<Grid
v-model="settings.doc.dropdown_items"
doctype="CRM Dropdown Item"
parentDoctype="FCRM Settings"
parentFieldname="dropdown_items"
/>
</div>
</div>
</div>
<ErrorMessage :message="settings.save.error" />
<div v-if="errorMessage">
<ErrorMessage :message="__(errorMessage)" />
</div>
</div>
</template>
<script setup>
import ImageUploader from '@/components/Controls/ImageUploader.vue'
import Grid from '@/components/Controls/Grid.vue'
import { FormControl, Badge, ErrorMessage } from 'frappe-ui'
import { FormControl, ErrorMessage } from 'frappe-ui'
import { getSettings } from '@/stores/settings'
import { showSettings } from '@/composables/settings'
import { ref } from 'vue'
const { _settings: settings, setupBrand } = getSettings()
@ -142,4 +131,7 @@ function updateSettings() {
},
})
}
const emit = defineEmits(['updateStep'])
const errorMessage = ref('')
</script>

View File

@ -0,0 +1,54 @@
<template>
<div class="flex h-full flex-col gap-6 p-8 text-ink-gray-8">
<div class="flex flex-col gap-1">
<h2 class="flex gap-2 text-xl font-semibold leading-none h-5">
{{ __('General') }}
</h2>
<p class="text-p-base text-ink-gray-6">
{{ __('Configure general settings for your CRM') }}
</p>
</div>
<div class="flex-1 flex flex-col overflow-y-auto">
<template v-for="(setting, i) in settings" :key="setting.name">
<li
class="flex items-center justify-between p-3 cursor-pointer hover:bg-surface-menu-bar rounded"
@click="() => emit('updateStep', setting.name)"
>
<div class="flex flex-col">
<div class="text-base font-medium text-ink-gray-7 truncate">
{{ __(setting.label) }}
</div>
<div class="text-p-base text-ink-gray-5 truncate">
{{ __(setting.description) }}
</div>
</div>
<div>
<FeatherIcon name="chevron-right" class="text-ink-gray-7 size-4" />
</div>
</li>
<div
v-if="settings !== i + 1"
class="h-px border-t mx-2 border-outline-gray-modals"
/>
</template>
</div>
</div>
</template>
<script setup>
const emit = defineEmits(['updateStep'])
const settings = [
{
name: 'brand-settings',
label: 'Brand settings',
description: 'Configure your brand name, logo and favicon',
},
{
name: 'home-actions',
label: 'Home actions',
description: 'Configure actions that appear on the home dropdown',
},
]
</script>

View File

@ -0,0 +1,31 @@
<template>
<component :is="getComponent(step)" :data="data" @updateStep="updateStep" />
</template>
<script setup>
import GeneralSettings from './GeneralSettings.vue'
import BrandSettings from './BrandSettings.vue'
import HomeActions from './HomeActions.vue'
import { ref } from 'vue'
const step = ref('general-settings')
const data = ref(null)
function updateStep(newStep, _data) {
step.value = newStep
data.value = _data
}
function getComponent(step) {
switch (step) {
case 'general-settings':
return GeneralSettings
case 'brand-settings':
return BrandSettings
case 'home-actions':
return HomeActions
default:
return null
}
}
</script>

View File

@ -0,0 +1,60 @@
<template>
<div class="flex h-full flex-col gap-6 p-8 text-ink-gray-8">
<!-- Header -->
<div class="flex justify-between">
<div class="flex gap-1 -ml-4 w-9/12">
<Button
variant="ghost"
icon-left="chevron-left"
:label="__('Home actions')"
size="md"
@click="() => emit('updateStep', 'general-settings')"
class="text-xl !h-7 font-semibold hover:bg-transparent focus:bg-transparent focus:outline-none focus:ring-0 focus:ring-offset-0 focus-visible:none active:bg-transparent active:outline-none active:ring-0 active:ring-offset-0 active:text-ink-gray-5"
/>
</div>
<div class="flex item-center space-x-2 w-3/12 justify-end">
<Button
:label="__('Update')"
icon-left="plus"
variant="solid"
:disabled="!settings.isDirty"
:loading="settings.loading"
@click="updateSettings"
/>
</div>
</div>
<!-- Fields -->
<div class="flex flex-1 flex-col gap-4 overflow-y-auto">
<Grid
v-model="settings.doc.dropdown_items"
doctype="CRM Dropdown Item"
parentDoctype="FCRM Settings"
parentFieldname="dropdown_items"
/>
</div>
<div v-if="errorMessage">
<ErrorMessage :message="__(errorMessage)" />
</div>
</div>
</template>
<script setup>
import Grid from '@/components/Controls/Grid.vue'
import { ErrorMessage } from 'frappe-ui'
import { getSettings } from '@/stores/settings'
import { showSettings } from '@/composables/settings'
import { ref } from 'vue'
const { _settings: settings } = getSettings()
const emit = defineEmits(['updateStep'])
const errorMessage = ref('')
function updateSettings() {
settings.save.submit(null, {
onSuccess: () => {
showSettings.value = false
},
})
}
</script>

View File

@ -47,7 +47,7 @@ import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
import Email2Icon from '@/components/Icons/Email2Icon.vue'
import EmailTemplateIcon from '@/components/Icons/EmailTemplateIcon.vue'
import Users from '@/components/Settings/Users.vue'
import GeneralSettings from '@/components/Settings/GeneralSettings.vue'
import GeneralSettingsPage from '@/components/Settings/General/GeneralSettingsPage.vue'
import InviteUserPage from '@/components/Settings/InviteUserPage.vue'
import ProfileSettings from '@/components/Settings/ProfileSettings.vue'
import WhatsAppSettings from '@/components/Settings/WhatsAppSettings.vue'
@ -88,7 +88,7 @@ const tabs = computed(() => {
{
label: __('General'),
icon: 'settings',
component: markRaw(GeneralSettings),
component: markRaw(GeneralSettingsPage),
condition: () => isManager(),
},
{