2026-02-24 20:44:16 +00:00
|
|
|
import { AdaptableCard } from '@/components/shared'
|
|
|
|
|
import Container from '@/components/shared/Container'
|
|
|
|
|
import {
|
|
|
|
|
Button,
|
|
|
|
|
Card,
|
|
|
|
|
Checkbox,
|
|
|
|
|
FormContainer,
|
|
|
|
|
FormItem,
|
|
|
|
|
Input,
|
|
|
|
|
Menu,
|
|
|
|
|
Select,
|
|
|
|
|
Tooltip,
|
|
|
|
|
toast,
|
|
|
|
|
} from '@/components/ui'
|
|
|
|
|
import Notification from '@/components/ui/Notification'
|
|
|
|
|
import { APP_NAME } from '@/constants/app.constant'
|
|
|
|
|
import { MainGroupedSettingDto } from '@/proxy/settings/models'
|
|
|
|
|
import { getList, updateSettingValues } from '@/services/setting-ui.service'
|
|
|
|
|
import { useStoreActions, useStoreState } from '@/store'
|
2026-03-27 13:49:15 +00:00
|
|
|
import { SelectBoxOption } from '@/types/shared'
|
2026-02-24 20:44:16 +00:00
|
|
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
|
|
|
|
import { Field, FieldProps, Form, Formik } from 'formik'
|
|
|
|
|
import isEmpty from 'lodash/isEmpty'
|
|
|
|
|
import { useEffect, useMemo, useState } from 'react'
|
|
|
|
|
import { Helmet } from 'react-helmet'
|
|
|
|
|
import { FaQuestionCircle } from 'react-icons/fa'
|
|
|
|
|
|
|
|
|
|
function getOptions(selectOptions?: Record<string, string>) {
|
2026-03-27 13:49:15 +00:00
|
|
|
const options: SelectBoxOption[] = []
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
|
|
|
if (!selectOptions) {
|
|
|
|
|
return options
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Object.entries(selectOptions).forEach(([key, value]) =>
|
|
|
|
|
options.push({
|
|
|
|
|
value: key,
|
|
|
|
|
label: value,
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return options
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Settings = () => {
|
|
|
|
|
const { translate } = useLocalization()
|
|
|
|
|
const [list, setList] = useState<MainGroupedSettingDto[]>([])
|
|
|
|
|
const [mainGroups, setMainGroups] = useState<string[]>([])
|
|
|
|
|
const [activeMainGroupKey, setActiveMainGroupKey] = useState<string>()
|
|
|
|
|
const activeMainGroup = useMemo(
|
|
|
|
|
() => list.find((a) => a.groupName === activeMainGroupKey),
|
|
|
|
|
[activeMainGroupKey, list],
|
|
|
|
|
)
|
|
|
|
|
const { getConfig } = useStoreActions((a) => a.abpConfig)
|
|
|
|
|
const { setMode } = useStoreActions((actions) => actions.theme)
|
|
|
|
|
|
|
|
|
|
const onFormSubmit = async (
|
|
|
|
|
values: Record<string, string>,
|
|
|
|
|
setSubmitting: (isSubmitting: boolean) => void,
|
|
|
|
|
activeGroupName?: string,
|
|
|
|
|
) => {
|
|
|
|
|
//Dark Mode verildimi ?
|
2026-03-27 13:49:15 +00:00
|
|
|
if (values.App_SiteManagement_Theme_Style) {
|
2026-02-24 20:44:16 +00:00
|
|
|
setMode(
|
2026-03-27 13:49:15 +00:00
|
|
|
values.App_SiteManagement_Theme_Style.includes('.dark') ? 'dark' : 'light',
|
2026-02-24 20:44:16 +00:00
|
|
|
)
|
|
|
|
|
}
|
2026-03-27 13:49:15 +00:00
|
|
|
console.log(values)
|
2026-02-24 20:44:16 +00:00
|
|
|
const resp = await updateSettingValues(values)
|
|
|
|
|
if (resp.status === 204) {
|
|
|
|
|
await fetchData(activeGroupName)
|
|
|
|
|
toast.push(
|
|
|
|
|
<Notification
|
|
|
|
|
title={
|
|
|
|
|
translate('::' + activeGroupName) +
|
|
|
|
|
' ' +
|
2026-03-27 13:49:15 +00:00
|
|
|
translate('::SuccessfullySaved')
|
2026-02-24 20:44:16 +00:00
|
|
|
}
|
|
|
|
|
type="success"
|
|
|
|
|
/>,
|
|
|
|
|
{
|
|
|
|
|
placement: 'top-end',
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
toast.push(<Notification title={resp?.error?.message} type="danger" />, {
|
|
|
|
|
placement: 'top-end',
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
//getConfig değiştiriliyor.
|
|
|
|
|
getConfig(false)
|
|
|
|
|
setSubmitting(false)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const mode = useStoreState((state) => state.theme.mode)
|
|
|
|
|
|
|
|
|
|
const fetchData = async (activeGroupName?: string) => {
|
|
|
|
|
const result = await getList()
|
|
|
|
|
|
|
|
|
|
if (result.data) {
|
|
|
|
|
setList(result.data)
|
|
|
|
|
if (activeGroupName) {
|
|
|
|
|
setActiveMainGroupKey(activeGroupName)
|
|
|
|
|
} else {
|
|
|
|
|
setActiveMainGroupKey(result.data.length ? result.data[0].groupName : '')
|
|
|
|
|
}
|
|
|
|
|
setMainGroups(result.data.map((a) => a.groupName))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (isEmpty(list)) {
|
|
|
|
|
fetchData()
|
|
|
|
|
}
|
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Container className="h-full">
|
|
|
|
|
<Helmet
|
|
|
|
|
titleTemplate={`%s | ${APP_NAME}`}
|
|
|
|
|
title={translate('::' + 'App.Settings')}
|
|
|
|
|
defaultTitle={APP_NAME}
|
|
|
|
|
></Helmet>
|
|
|
|
|
|
|
|
|
|
<div className="flex flex-col md:flex-row gap-4">
|
|
|
|
|
<div className="md:w-2/12 min-w-fit">
|
|
|
|
|
<Menu className="p-2" variant={mode} defaultActiveKeys={[activeMainGroupKey ?? '']}>
|
|
|
|
|
{mainGroups.map((group) => (
|
|
|
|
|
<Menu.MenuItem
|
|
|
|
|
key={group}
|
|
|
|
|
className="break-all whitespace-normal"
|
|
|
|
|
eventKey={group}
|
|
|
|
|
onSelect={() => setActiveMainGroupKey(group)}
|
|
|
|
|
>
|
|
|
|
|
{translate('::' + group)}
|
|
|
|
|
</Menu.MenuItem>
|
|
|
|
|
))}
|
|
|
|
|
</Menu>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="md:w-10/12 w-full">
|
|
|
|
|
<AdaptableCard>
|
|
|
|
|
{activeMainGroup?.subGroups.map((subGroup) => (
|
|
|
|
|
<Card
|
|
|
|
|
key={subGroup.subGroupName}
|
|
|
|
|
className="mb-5 "
|
|
|
|
|
header={translate('::' + subGroup.subGroupName)}
|
|
|
|
|
>
|
|
|
|
|
<Formik
|
|
|
|
|
initialValues={subGroup.settings.reduce((acc: any, cur) => {
|
|
|
|
|
if (!cur.code) {
|
|
|
|
|
return acc
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cur.dataType === 'Bool') {
|
|
|
|
|
acc[cur.code] = cur.valueBool
|
|
|
|
|
} else {
|
|
|
|
|
acc[cur.code] = cur.value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return acc
|
|
|
|
|
}, {})}
|
|
|
|
|
onSubmit={(values, { setSubmitting }) => {
|
|
|
|
|
setSubmitting(true)
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
onFormSubmit(values, setSubmitting, activeMainGroupKey)
|
|
|
|
|
}, 1000)
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{({ values, touched, errors, isSubmitting }) => (
|
|
|
|
|
<Form>
|
|
|
|
|
<FormContainer>
|
|
|
|
|
{subGroup.settings.map((setting) => (
|
|
|
|
|
<FormItem
|
|
|
|
|
key={setting.code}
|
|
|
|
|
label={translate('::' + setting.name) + ' (' + setting.providers?.replaceAll('|', ', ') + ')'}
|
|
|
|
|
extra={
|
|
|
|
|
<Tooltip title={translate('::' + setting.description)}>
|
|
|
|
|
<FaQuestionCircle className="text-lg cursor-pointer ml-1" />
|
|
|
|
|
</Tooltip>
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<>
|
|
|
|
|
{setting.dataType === 'Text' && (
|
|
|
|
|
<Field type="text" name={setting.code} component={Input} />
|
|
|
|
|
)}
|
|
|
|
|
{setting.dataType === 'Number' && (
|
|
|
|
|
<Field type="number" name={setting.code} component={Input} />
|
|
|
|
|
)}
|
|
|
|
|
{setting.dataType === 'Memo' && (
|
|
|
|
|
<Field type="text" name={setting.code} textArea component={Input} />
|
|
|
|
|
)}
|
|
|
|
|
{setting.dataType === 'Bool' && (
|
|
|
|
|
<Field name={setting.code} component={Checkbox}></Field>
|
|
|
|
|
)}
|
|
|
|
|
{setting.dataType === 'List' && (
|
|
|
|
|
<Field name={setting.code}>
|
|
|
|
|
{({ field, form }: FieldProps<any>) => (
|
|
|
|
|
<Select
|
|
|
|
|
field={field}
|
|
|
|
|
form={form}
|
|
|
|
|
options={getOptions(setting.selectOptions)}
|
|
|
|
|
value={getOptions(setting.selectOptions).filter(
|
|
|
|
|
(option) => option.value === values[setting.code],
|
|
|
|
|
)}
|
|
|
|
|
onChange={(option) =>
|
|
|
|
|
form.setFieldValue(field.name, option?.value)
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</Field>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
|
|
|
|
</FormItem>
|
|
|
|
|
))}
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="float-right">
|
|
|
|
|
<Button
|
|
|
|
|
size="sm"
|
|
|
|
|
variant="solid"
|
|
|
|
|
className="ltr:mr-2 rtl:ml-2"
|
|
|
|
|
type="submit"
|
|
|
|
|
loading={isSubmitting}
|
|
|
|
|
>
|
|
|
|
|
{isSubmitting
|
|
|
|
|
? translate('::SavingWithThreeDot')
|
|
|
|
|
: translate('::Save')}
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</FormItem>
|
|
|
|
|
</FormContainer>
|
|
|
|
|
</Form>
|
|
|
|
|
)}
|
|
|
|
|
</Formik>
|
|
|
|
|
</Card>
|
|
|
|
|
))}
|
|
|
|
|
</AdaptableCard>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</Container>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default Settings
|