erp-platform/ui/src/views/admin/chart/ChartEdit.tsx

1535 lines
58 KiB
TypeScript
Raw Normal View History

2025-09-25 14:40:16 +00:00
import {
2025-05-06 06:45:49 +00:00
Alert,
Button,
Card,
Checkbox,
Dialog,
FormContainer,
FormItem,
Input,
Notification,
Select,
Tabs,
toast,
} from '@/components/ui'
import TabContent from '@/components/ui/Tabs/TabContent'
import TabList from '@/components/ui/Tabs/TabList'
import TabNav from '@/components/ui/Tabs/TabNav'
import { getRoles, getUsers } from '@/services/identity.service'
2025-05-06 06:45:49 +00:00
import {
deleteChartJsonItem,
getChartByCode,
putChartJsonItem,
putCharts,
} from '@/services/chart.service'
2025-05-06 06:45:49 +00:00
import { SelectBoxOption } from '@/shared/types'
import { useStoreState } from '@/store'
import { useLocalization } from '@/utils/hooks/useLocalization'
import setNull from '@/utils/setNull'
import { Field, FieldArray, FieldProps, Form, Formik, FormikProps, getIn } from 'formik'
import { useEffect, useState } from 'react'
import { Helmet } from 'react-helmet'
import { Link, useParams } from 'react-router-dom'
import { object, string } from 'yup'
import {
chartAnnotationTypeListOptions,
chartArgumentAxisPositionListOptions,
chartArgumentAxisTypeListOptions,
chartBreakStyleLineListOptions,
chartSeriesDashStyleOptions,
chartSeriesSelectionModeOptions,
chartSeriesTypeOptions,
chartTitleWordWrapListOptions,
} from './options'
import { ChartDialogType, ChartOperation } from './types'
import { IdentityRoleDto, IdentityUserDto } from '@/proxy/admin/models'
import {
BreakDto,
ChartAnnotationDto,
ChartEditDto,
ChartPanesDto,
ChartSeriesDto,
ChartValueAxisDto,
} from '@/proxy/charts/models'
2025-08-15 13:42:27 +00:00
import { Container } from '@/components/shared'
2025-09-25 14:40:16 +00:00
import ChartEditDetailsTab from './edit/ChartTabDetails'
import ChartEditDatabaseTab from './edit/ChartTabDatabase'
import ChartEditCommonSettingsTab from './edit/ChartTabCommonSettings'
import ChartEditPermissionsTab from './edit/ChartTabPermissions'
import ChartEditSeriesTab from './edit/ChartTabSeries'
import ChartEditAxisTab from './edit/ChartTabAxis'
import ChartEditPanesTab from './edit/ChartTabPanes'
import ChartEditCrosshairTab from './edit/ChartTabCrosshair'
import ChartTabAnimation from './edit/ChartTabAnimation'
import ChartEditExportTab from './edit/ChartTabExport'
import ChartTabLegend from './edit/ChartTabLegend'
import ChartTabAnnotations from './edit/ChartTabAnnotations'
import ChartEditZoomAndPanTab from './edit/ChartTabZoomAndPan'
import { getDataSources } from '@/proxy/data-source'
import { tooltipFormatListOptions } from '@/shared/options'
import { FaMinus } from 'react-icons/fa'
import { ROUTES_ENUM } from '@/routes/route.constant'
2025-05-06 06:45:49 +00:00
const chartPanesValidationSchema = object().shape({
name: string().required(),
})
const chartSeriesValidationSchema = object().shape({
name: string().required(),
})
const chartAxisValidationSchema = object().shape({
name: string().required(),
title: string().required(),
})
const chartAnnotationsValidationSchema = object().shape({
name: string().required(),
})
const fieldFeedback = (form: FormikProps<BreakDto>, name: string) => {
const error = getIn(form.errors, name)
const touch = getIn(form.touched, name)
return {
errorMessage: error || '',
invalid: typeof touch === 'undefined' ? false : error && touch,
}
}
const chartValidationSchema = object().shape({
cultureName: string().required(),
chartCode: string().required(),
})
2025-09-25 14:40:16 +00:00
export interface DatabaseOperation {
2025-05-06 06:45:49 +00:00
isOpen: ChartDialogType
id: string
operation: ChartOperation
index: number
panesValues?: ChartPanesDto
seriesValues?: ChartSeriesDto
annotationsValues?: ChartAnnotationDto
axisValues?: ChartValueAxisDto
}
const defaultDatabaseOperation: DatabaseOperation = {
isOpen: '',
id: '',
operation: 'select',
index: -1,
}
2025-09-25 14:40:16 +00:00
export interface ConfirmDelete {
2025-05-06 06:45:49 +00:00
isOpen: boolean
id: string
index: number
fieldName: ChartDialogType
}
const defaultConfirmDelete: ConfirmDelete = {
isOpen: false,
id: '',
index: -1,
fieldName: 'pane',
}
function ChartEdit() {
const { chartCode } = useParams()
const { translate } = useLocalization()
const [dataSourceList, setDataSourceList] = useState<SelectBoxOption[]>([])
2025-09-25 14:40:16 +00:00
const languages = useStoreState((state) => state.abpConfig.config?.localization.languages)
2025-05-06 06:45:49 +00:00
const permissions: Record<string, boolean> | undefined = useStoreState(
(state) => state.abpConfig.config?.auth.grantedPolicies,
)
const [chartValues, setChartValues] = useState<ChartEditDto>()
const [langOptions, setLangOptions] = useState<SelectBoxOption[]>([])
const [roleList, setRoleList] = useState<SelectBoxOption[]>([])
const [userList, setUserList] = useState<SelectBoxOption[]>([])
const [permissionOptions, setPermissionOptions] = useState<SelectBoxOption[]>([])
const [confirmDelete, setConfirmDelete] = useState<ConfirmDelete>(defaultConfirmDelete)
const [databaseOperationsModalData, setDatabaseOperationsModalData] =
useState<DatabaseOperation>(defaultDatabaseOperation)
2025-09-25 14:40:16 +00:00
const onSubmit = async (editType: string, values: Partial<ChartEditDto>): Promise<void> => {
try {
await putCharts({
...chartValues,
...values, // sadece güncellenen tab'ın değerleri override edilir
} as ChartEditDto) // chartValues null olamaz çünkü form ancak chartValues yüklendikten sonra render ediliyor
toast.push(
<Notification type="success" duration={2000}>
{`${editType} kaydedildi.`}
</Notification>,
{ placement: 'top-end' },
)
await getChartValues()
} catch (error) {
toast.push(<Notification type="danger">Hata: {String(error)}</Notification>)
}
}
2025-05-06 06:45:49 +00:00
const valueAxisList = () => {
return chartValues?.valueAxisDto.map((key: ChartValueAxisDto) => ({
value: key.name,
label: key.name,
}))
}
const valuePaneList = () => {
return chartValues?.panesDto.map((key: ChartPanesDto) => ({
value: key.name,
label: key.name,
}))
}
const SeriesList = () => {
return chartValues?.seriesDto.map((key: ChartSeriesDto) => ({
value: key.name,
label: key.name,
}))
}
useEffect(() => {
if (languages) {
setLangOptions(
languages.map((lang) => ({
value: lang.cultureName,
label: lang.displayName,
})),
)
}
}, [languages])
useEffect(() => {
if (permissions) {
setPermissionOptions(
Object.keys(permissions).map((key) => {
return {
value: key,
label: key,
}
}),
)
}
}, [permissions])
const getRoleList = async () => {
const response = await getRoles()
if (response.data?.items) {
setRoleList(
response.data.items.map((role: IdentityRoleDto) => ({
value: role.id,
label: role.name,
})),
)
}
}
const getUserList = async () => {
const response = await getUsers()
if (response.data?.items) {
setUserList(
response.data.items.map((user: IdentityUserDto) => ({
value: user.id,
label: user.name,
})),
)
}
}
const getChartValues = async () => {
if (!chartCode) return
const res = await getChartByCode(chartCode)
setNull(res.data)
setChartValues(res.data)
}
const getDataSourceList = async () => {
const response = await getDataSources()
if (response.data?.items) {
setDataSourceList(
response.data.items.map((a) => ({
value: a.code,
label: a.code,
})),
)
}
}
useEffect(() => {
getChartValues()
getRoleList()
getUserList()
getDataSourceList()
}, [chartCode])
return chartValues && roleList && userList && permissionOptions ? (
2025-08-15 13:42:27 +00:00
<Container>
2025-08-14 07:10:56 +00:00
<Helmet
2025-09-13 11:46:34 +00:00
titleTemplate="%s | Sözsoft Kurs Platform"
2025-08-14 07:10:56 +00:00
title={chartCode}
2025-09-13 11:46:34 +00:00
defaultTitle="Sözsoft Kurs Platform"
2025-08-14 07:10:56 +00:00
></Helmet>
2025-05-06 06:45:49 +00:00
<Formik
initialValues={{ ...chartValues }}
validationSchema={chartValidationSchema}
onSubmit={async (values, { resetForm, setSubmitting }) => {
setSubmitting(true)
await putCharts({ ...values })
toast.push(
<Notification type="success" duration={2000}>
{'Chart Bilgileri Kaydedildi.'}
</Notification>,
{
placement: 'top-end',
2025-05-06 06:45:49 +00:00
},
)
setSubmitting(false)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
<Form>
<FormContainer size="sm">
<div className="lg:flex items-center justify-between mb-4 gap-3">
<div className="mb-4 lg:mb-0">
<h4>
2025-09-25 14:40:16 +00:00
<Link
to={ROUTES_ENUM.protected.admin.chart.replace('::chartCode', chartCode || '')}
>
🔙 {chartCode}
</Link>
2025-05-06 06:45:49 +00:00
</h4>
{chartValues.isTenant && (
<Alert showIcon className="mb-4" type="warning">
Bu bir MULTI TENANT form'dur, veri kaybı olmaması için, sorgularda TENANTID
parametresini kullanmayı unutmayınız.
</Alert>
)}
</div>
</div>
<Tabs defaultValue="details" variant="pill">
<TabList className="flex-wrap border-b mb-2 bg-slate-50">
<TabNav value="details">Details</TabNav>
<TabNav value="database">Database</TabNav>
<TabNav value="permissions">Permissions</TabNav>
2025-09-25 14:40:16 +00:00
<TabNav value="commonSettings">Common</TabNav>
2025-05-06 06:45:49 +00:00
<TabNav value="series">Series</TabNav>
<TabNav value="axis">Axis</TabNav>
<TabNav value="panes">Panes</TabNav>
<TabNav value="animationsOptions">Animations</TabNav>
<TabNav value="crosshairOptions">Crosshair</TabNav>
<TabNav value="exportSettings">Export</TabNav>
<TabNav value="legendSettings">Legend</TabNav>
<TabNav value="zoomAndPanSettings">Zoom & Pan</TabNav>
<TabNav value="annotations">Annotations</TabNav>
</TabList>
<TabContent value="details">
2025-09-25 14:40:16 +00:00
<ChartEditDetailsTab
values={values}
errors={errors}
touched={touched}
langOptions={langOptions}
roleList={roleList}
userList={userList}
/>
2025-05-06 06:45:49 +00:00
</TabContent>
<TabContent value="database">
2025-09-25 14:40:16 +00:00
<ChartEditDatabaseTab
values={values}
errors={errors}
touched={touched}
dataSourceList={dataSourceList}
/>
2025-05-06 06:45:49 +00:00
</TabContent>
<TabContent value="commonSettings">
2025-09-25 14:40:16 +00:00
<ChartEditCommonSettingsTab values={values} errors={errors} touched={touched} />
2025-05-06 06:45:49 +00:00
</TabContent>
<TabContent value="permissions">
2025-09-25 14:40:16 +00:00
<ChartEditPermissionsTab
values={values}
errors={errors}
touched={touched}
permissionOptions={permissionOptions}
/>
2025-05-06 06:45:49 +00:00
</TabContent>
<TabContent value="series">
2025-09-25 14:40:16 +00:00
<ChartEditSeriesTab
values={values}
errors={errors}
touched={touched}
chartValues={chartValues}
setDatabaseOperationsModalData={setDatabaseOperationsModalData}
setConfirmDelete={setConfirmDelete}
valueAxisList={valueAxisList}
valuePaneList={valuePaneList}
/>
2025-05-06 06:45:49 +00:00
</TabContent>
<TabContent value="axis">
2025-09-25 14:40:16 +00:00
<ChartEditAxisTab
values={values}
errors={errors}
touched={touched}
chartValues={chartValues}
setDatabaseOperationsModalData={setDatabaseOperationsModalData}
setConfirmDelete={setConfirmDelete}
/>
2025-05-06 06:45:49 +00:00
</TabContent>
<TabContent value="panes">
2025-09-25 14:40:16 +00:00
<ChartEditPanesTab
values={values}
errors={errors}
touched={touched}
chartValues={chartValues}
setDatabaseOperationsModalData={setDatabaseOperationsModalData}
setConfirmDelete={setConfirmDelete}
/>
2025-05-06 06:45:49 +00:00
</TabContent>
<TabContent value="animationsOptions">
2025-09-25 14:40:16 +00:00
<ChartTabAnimation values={values} errors={errors} touched={touched} />
2025-05-06 06:45:49 +00:00
</TabContent>
<TabContent value="crosshairOptions">
2025-09-25 14:40:16 +00:00
<ChartEditCrosshairTab values={values} errors={errors} touched={touched} />
2025-05-06 06:45:49 +00:00
</TabContent>
<TabContent value="exportSettings">
2025-09-25 14:40:16 +00:00
<ChartEditExportTab errors={errors} touched={touched} />
2025-05-06 06:45:49 +00:00
</TabContent>
<TabContent value="legendSettings">
2025-09-25 14:40:16 +00:00
<ChartTabLegend values={values} errors={errors} touched={touched} />
2025-05-06 06:45:49 +00:00
</TabContent>
<TabContent value="zoomAndPanSettings">
2025-09-25 14:40:16 +00:00
<ChartEditZoomAndPanTab values={values} errors={errors} touched={touched} />
2025-05-06 06:45:49 +00:00
</TabContent>
<TabContent value="annotations">
2025-09-25 14:40:16 +00:00
<ChartTabAnnotations
values={values}
errors={errors}
touched={touched}
chartValues={chartValues}
setDatabaseOperationsModalData={setDatabaseOperationsModalData}
setConfirmDelete={setConfirmDelete}
SeriesList={SeriesList}
/>
2025-05-06 06:45:49 +00:00
</TabContent>
</Tabs>
<div className="mt-4">
<Button block variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
</Button>
</div>
</FormContainer>
</Form>
)}
</Formik>
<Dialog
id="paneOperation"
contentClassName="pb-2 px-2"
isOpen={databaseOperationsModalData.isOpen == 'pane'}
onClose={() => setDatabaseOperationsModalData(defaultDatabaseOperation)}
onRequestClose={() => setDatabaseOperationsModalData(defaultDatabaseOperation)}
>
<h5 className="mb-4">{databaseOperationsModalData.index === -1 ? 'Add' : 'Update'}</h5>
<Formik
initialValues={
databaseOperationsModalData.panesValues ?? {
id: '',
backgroundColor: '',
height: 250,
name: '',
}
}
validationSchema={chartPanesValidationSchema}
onSubmit={async (values, { setSubmitting }) => {
setSubmitting(true)
await putChartJsonItem({
id: chartValues.id,
chartCode: chartValues.chartCode,
index: databaseOperationsModalData.index,
fieldName: 'pane',
itemPane: { ...values },
})
toast.push(
<Notification type="success" duration={2000}>
{databaseOperationsModalData.index === -1
? 'Kayıt eklendi.'
: 'Kayıt Değiştirildi.'}
</Notification>,
{
placement: 'top-end',
2025-05-06 06:45:49 +00:00
},
)
getChartValues()
setSubmitting(false)
setDatabaseOperationsModalData(defaultDatabaseOperation)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
<Form>
<FormContainer>
<div className="max-h-96 overflow-y-auto p-2">
<FormItem
label="Name"
invalid={errors.name && touched.name}
errorMessage={errors.name}
>
<Field type="text" name="name" component={Input} />
</FormItem>
<FormItem
label="Background Color"
invalid={errors.backgroundColor && touched.backgroundColor}
errorMessage={errors.backgroundColor}
>
<Field type="text" name="backgroundColor" component={Input} />
</FormItem>
<FormItem
label="Height"
invalid={errors.height && touched.height}
errorMessage={errors.height}
>
<Field type="number" name="height" component={Input} />
</FormItem>
</div>
<div className="text-right mt-4">
<Button block variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
</Button>
</div>
</FormContainer>
</Form>
)}
</Formik>
</Dialog>
<Dialog
id="seriesOperation"
width={900}
contentClassName="pb-2 px-2"
isOpen={databaseOperationsModalData.isOpen == 'serie'}
onClose={() => setDatabaseOperationsModalData(defaultDatabaseOperation)}
onRequestClose={() => setDatabaseOperationsModalData(defaultDatabaseOperation)}
>
<h5 className="mb-4">{databaseOperationsModalData.index === -1 ? 'Add' : 'Update'}</h5>
<Formik
initialValues={
databaseOperationsModalData.seriesValues ?? {
id: '',
argumentField: '',
axis: '',
barOverlapGroup: '',
barPadding: 0,
barWidth: 0,
color: '',
cornerRadius: 0,
dashStyle: 'solid',
ignoreEmptyPoints: false,
name: '',
pane: '',
rangeValue1Field: '',
rangeValue2Field: '',
selectionMode: 'none',
showInLegend: true,
type: 'line',
valueField: '',
visible: true,
width: 2,
label: {
visible: false,
backgroundColor: '#f05b41',
2025-05-06 06:45:49 +00:00
customizeText: '',
format: '',
font: null,
2025-05-06 06:45:49 +00:00
},
}
}
validationSchema={chartSeriesValidationSchema}
onSubmit={async (values, { resetForm, setSubmitting }) => {
setSubmitting(true)
await putChartJsonItem({
chartCode: chartValues.chartCode,
id: chartValues.id,
index: databaseOperationsModalData.index,
fieldName: 'serie',
2025-09-22 14:08:42 +00:00
itemSerie: { ...values } as ChartSeriesDto,
2025-05-06 06:45:49 +00:00
})
toast.push(
<Notification type="success" duration={2000}>
{databaseOperationsModalData.index === -1
? 'Kayıt eklendi.'
: 'Kayıt Değiştirildi.'}
</Notification>,
{
placement: 'top-end',
2025-05-06 06:45:49 +00:00
},
)
getChartValues()
setSubmitting(false)
setDatabaseOperationsModalData(defaultDatabaseOperation)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
<Form>
<FormContainer>
<div className="max-h-96 overflow-y-auto p-2">
<FormItem
label="Visible"
invalid={errors.visible && touched.visible}
errorMessage={errors.visible}
>
<Field name="visible" component={Checkbox} />
</FormItem>
<FormItem
label="Show In Legend"
invalid={errors.showInLegend && touched.showInLegend}
errorMessage={errors.showInLegend}
>
<Field name="showInLegend" component={Checkbox} />
</FormItem>
<FormItem
label="Ignore Empty Points"
invalid={errors.ignoreEmptyPoints && touched.ignoreEmptyPoints}
errorMessage={errors.ignoreEmptyPoints}
>
<Field name="ignoreEmptyPoints" component={Checkbox} />
</FormItem>
<FormItem
label="Type"
invalid={errors.type && touched.type}
errorMessage={errors.type}
>
<Field type="text" name="type">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
options={chartSeriesTypeOptions}
isClearable={true}
value={chartSeriesTypeOptions.filter(
(option) => option.value === values.type,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Name"
invalid={errors.name && touched.name}
errorMessage={errors.name}
>
<Field type="text" name="name" component={Input} />
</FormItem>
<FormItem
label="Argument Field"
invalid={errors.argumentField && touched.argumentField}
errorMessage={errors.argumentField}
>
<Field type="text" name="argumentField" component={Input} />
</FormItem>
<FormItem
label="Value Field"
invalid={errors.valueField && touched.valueField}
errorMessage={errors.valueField}
>
<Field type="text" name="valueField" component={Input} />
</FormItem>
<FormItem
label="Axis"
invalid={errors.axis && touched.axis}
errorMessage={errors.axis}
>
<Field type="text" name="axis">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
options={valueAxisList()}
isClearable={true}
value={valueAxisList()?.find((option) => option.value === values.axis)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Pane"
invalid={errors.pane && touched.pane}
errorMessage={errors.pane}
>
<Field type="text" name="pane">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
options={valuePaneList()}
isClearable={true}
value={valuePaneList()?.find((option) => option.value === values.pane)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Type"
invalid={errors.dashStyle && touched.dashStyle}
errorMessage={errors.dashStyle}
>
<Field type="text" name="dashStyle">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
options={chartSeriesDashStyleOptions}
isClearable={true}
value={chartSeriesDashStyleOptions.filter(
(option) => option.value === values.dashStyle,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Color"
invalid={errors.color && touched.color}
errorMessage={errors.color}
>
<Field type="text" name="color" component={Input} />
</FormItem>
<FormItem
label="Selection Mode"
invalid={errors.selectionMode && touched.selectionMode}
errorMessage={errors.selectionMode}
>
<Field type="text" name="selectionMode">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
options={chartSeriesSelectionModeOptions}
isClearable={true}
value={chartSeriesSelectionModeOptions.filter(
(option) => option.value === values.selectionMode,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Width"
invalid={errors.width && touched.width}
errorMessage={errors.width}
>
<Field type="number" name="width" component={Input} />
</FormItem>
<FormItem
label="Corner Radius"
invalid={errors.cornerRadius && touched.cornerRadius}
errorMessage={errors.cornerRadius}
>
<Field type="number" name="cornerRadius" component={Input} />
</FormItem>
<Card className="my-2" header="Label">
<FormItem label="Label Visible">
<Field name="label.visible" component={Checkbox} />
2025-05-06 06:45:49 +00:00
</FormItem>
2025-05-06 06:45:49 +00:00
<FormItem
label="Background Color"
invalid={errors.label?.backgroundColor && touched.label?.backgroundColor}
2025-05-06 06:45:49 +00:00
errorMessage={errors.label?.backgroundColor}
>
<Field type="text" name="label.backgroundColor" component={Input} />
2025-05-06 06:45:49 +00:00
</FormItem>
<FormItem
label="Format"
invalid={errors.label?.format && touched.label?.format}
2025-05-06 06:45:49 +00:00
errorMessage={errors.label?.format}
>
<Field type="text" name="label.format">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
options={tooltipFormatListOptions}
isClearable={true}
value={tooltipFormatListOptions.filter(
(option) => option.value === values.label.format,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Customize Text"
invalid={errors.label?.customizeText && touched.label?.customizeText}
2025-05-06 06:45:49 +00:00
errorMessage={errors.label?.customizeText}
>
<Field type="text" name="label.customizeText" component={Input} />
2025-05-06 06:45:49 +00:00
</FormItem>
</Card>
</div>
<div className="text-right mt-4">
<Button block variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
</Button>
</div>
</FormContainer>
</Form>
)}
</Formik>
</Dialog>
<Dialog
id="axisOperation"
width={900}
contentClassName="pb-2 px-2"
isOpen={databaseOperationsModalData.isOpen == 'axis'}
onClose={() => setDatabaseOperationsModalData(defaultDatabaseOperation)}
onRequestClose={() => setDatabaseOperationsModalData(defaultDatabaseOperation)}
>
<h5 className="mb-4">{databaseOperationsModalData.index === -1 ? 'Add' : 'Update'}</h5>
<Formik
initialValues={
databaseOperationsModalData.axisValues ?? {
grid: {
color: '#d3d3d3',
visible: false,
width: 1,
},
name: '',
position: '',
title: '',
valueType: '',
visible: false,
width: 0,
breaks: [
{
startValue: 0,
endValue: 0,
},
],
breakStyle: {
color: '#ababab',
line: 'waved',
width: 5,
},
type: '',
autoBreaksEnabled: false,
maxAutoBreakCount: 0,
}
}
validationSchema={chartAxisValidationSchema}
onSubmit={async (values, { setSubmitting }) => {
setSubmitting(true)
await putChartJsonItem({
chartCode: chartValues.chartCode,
id: chartValues.id,
index: databaseOperationsModalData.index,
fieldName: 'axis',
itemAxis: { ...values },
})
toast.push(
<Notification type="success" duration={2000}>
{databaseOperationsModalData.index === -1
? 'Kayıt eklendi.'
: 'Kayıt Değiştirildi.'}
</Notification>,
{
placement: 'top-end',
2025-05-06 06:45:49 +00:00
},
)
getChartValues()
setSubmitting(false)
setDatabaseOperationsModalData(defaultDatabaseOperation)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => {
const breaks = values.breaks
return (
<Form>
<FormContainer>
<div className="max-h-96 overflow-y-auto p-2">
<FormItem
label="Visible"
invalid={errors.visible && touched.visible}
errorMessage={errors.visible}
>
<Field name="visible" component={Checkbox} />
</FormItem>
<FormItem
label="Value Type"
invalid={errors.valueType && touched.valueType}
errorMessage={errors.valueType}
>
<Field type="text" name="valueType">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
options={chartArgumentAxisTypeListOptions}
isClearable={true}
value={chartArgumentAxisTypeListOptions.filter(
(option) => option.value === values.valueType,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Type"
invalid={errors.type && touched.type}
errorMessage={errors.type}
>
<Field type="text" name="type">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
options={chartArgumentAxisTypeListOptions}
isClearable={true}
value={chartArgumentAxisTypeListOptions.filter(
(option) => option.value === values.type,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Position"
invalid={errors.position && touched.position}
errorMessage={errors.position}
>
<Field type="text" name="position">
{({ field, form }: FieldProps<IdentityRoleDto>) => (
<Select
field={field}
form={form}
options={chartArgumentAxisPositionListOptions}
isClearable={true}
value={chartArgumentAxisPositionListOptions.filter(
(option) => option.value === values.position,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Name"
invalid={errors.name && touched.name}
errorMessage={errors.name}
>
<Field type="text" name="name" component={Input} />
</FormItem>
<FormItem
label="Title"
invalid={errors.title && touched.title}
errorMessage={errors.title}
>
<Field type="text" name="title" component={Input} />
</FormItem>
<FormItem
label="Width"
invalid={errors.width && touched.width}
errorMessage={errors.width}
>
<Field type="number" name="width" component={Input} />
</FormItem>
<Tabs defaultValue="grid" variant="pill">
<TabList>
<TabNav value="grid">Grid</TabNav>
<TabNav value="breakStyle">Break Style</TabNav>
<TabNav value="breaks">Breaks</TabNav>
</TabList>
<div className="pt-4">
<TabContent value="grid">
<FormItem
label="Visible"
invalid={errors.grid?.visible && touched.grid?.visible}
errorMessage={errors.grid?.visible}
>
<Field name="grid.visible" component={Checkbox} />
</FormItem>
<FormItem
label="Color"
invalid={errors.grid?.color && touched.grid?.color}
errorMessage={errors.grid?.color}
>
<Field type="text" name="grid.color" component={Input} />
</FormItem>
<FormItem
label="Width"
invalid={errors.grid?.width && touched.grid?.width}
errorMessage={errors.grid?.width}
>
<Field type="number" name="grid.width" component={Input} />
</FormItem>
</TabContent>
<TabContent value="breakStyle">
<FormItem
label="Color"
invalid={errors.breakStyle?.color && touched.breakStyle?.color}
errorMessage={errors.breakStyle?.color}
>
<Field type="text" name="breakStyle.color" component={Input} />
</FormItem>
<FormItem
label="Width"
invalid={errors.breakStyle?.width && touched.breakStyle?.width}
errorMessage={errors.breakStyle?.width}
>
<Field type="number" name="breakStyle.width" component={Input} />
</FormItem>
<FormItem
label="Line"
invalid={errors.breakStyle?.line && touched.breakStyle?.line}
errorMessage={errors.breakStyle?.line}
>
<Field type="text" name="breakStyle.line">
{({ field, form }: FieldProps<IdentityRoleDto>) => (
<Select
field={field}
form={form}
options={chartBreakStyleLineListOptions}
isClearable={true}
value={chartBreakStyleLineListOptions.filter(
(option) => option.value === values.breakStyle.line,
)}
onChange={(option) =>
form.setFieldValue(field.name, option?.value)
}
/>
)}
</Field>
</FormItem>
</TabContent>
<TabContent value="breaks">
<FieldArray name="breaks">
{({ form, remove, push }) => (
<div>
{breaks && breaks.length > 0
? breaks.map((_, index) => {
const startValueFeedBack = fieldFeedback(
form,
`breaks[${index}].startValue`,
)
const endValueFeedBack = fieldFeedback(
form,
`breaks[${index}].endValue`,
)
return (
<div key={index}>
<FormItem
layout="inline"
label="Start Value"
invalid={startValueFeedBack.invalid}
errorMessage={startValueFeedBack.errorMessage}
>
<Field
invalid={startValueFeedBack.invalid}
name={`breaks[${index}].startValue`}
type="number"
component={Input}
/>
</FormItem>
<FormItem
layout="inline"
label="End Value"
invalid={endValueFeedBack.invalid}
errorMessage={endValueFeedBack.errorMessage}
>
<Field
invalid={endValueFeedBack.invalid}
name={`breaks[${index}].endValue`}
type="number"
component={Input}
/>
</FormItem>
<Button
shape="circle"
type="button"
size="sm"
2025-08-16 21:17:18 +00:00
icon={<FaMinus />}
2025-05-06 06:45:49 +00:00
onClick={() => remove(index)}
/>
</div>
)
})
: null}
<div>
<Button
type="button"
className="ltr:mr-2 rtl:ml-2"
onClick={() => {
push({
startValue: 0,
endValue: 0,
})
}}
>
Add Break
</Button>
</div>
</div>
)}
</FieldArray>
</TabContent>
</div>
</Tabs>
</div>
<div className="text-right mt-4">
<Button block variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
</Button>
</div>
</FormContainer>
</Form>
)
}}
</Formik>
</Dialog>
<Dialog
id="annotationOperation"
width={900}
contentClassName="pb-2 px-2"
isOpen={databaseOperationsModalData.isOpen == 'annotation'}
onClose={() => setDatabaseOperationsModalData(defaultDatabaseOperation)}
onRequestClose={() => setDatabaseOperationsModalData(defaultDatabaseOperation)}
>
<h5 className="mb-4">{databaseOperationsModalData.index === -1 ? 'Add' : 'Update'}</h5>
<Formik
initialValues={
databaseOperationsModalData.annotationsValues ?? {
argument: '',
border: {
color: '#d3d3d3',
cornerRadius: 0,
dashStyle: 'solid',
visible: false,
width: 1,
},
color: '',
description: '',
font: {
color: '#FFFFFF',
family: '"Segoe UI", "Helvetica Neue", "Trebuchet MS", Verdana, sans-serif',
size: 12,
weight: 400,
},
height: 0,
image: '',
name: '',
offsetX: 0,
offsetY: 0,
paddingLeftRight: 0,
paddingTopBottom: 0,
series: '',
text: '',
tooltipEnabled: false,
type: '',
value: '',
width: 0,
wordWrap: '',
x: 0,
y: 0,
}
}
validationSchema={chartAnnotationsValidationSchema}
onSubmit={async (values, { resetForm, setSubmitting }) => {
setSubmitting(true)
await putChartJsonItem({
chartCode: chartValues.chartCode,
id: chartValues.id,
index: databaseOperationsModalData.index,
fieldName: 'annotation',
itemAnnotation: { ...values },
})
toast.push(
<Notification type="success" duration={2000}>
{databaseOperationsModalData.index === -1
? 'Kayıt eklendi.'
: 'Kayıt Değiştirildi.'}
</Notification>,
{
placement: 'top-end',
2025-05-06 06:45:49 +00:00
},
)
getChartValues()
setSubmitting(false)
setDatabaseOperationsModalData(defaultDatabaseOperation)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
<Form>
<FormContainer>
<div className="max-h-96 overflow-y-auto p-2">
<Tabs defaultValue="annotations_general">
<TabList>
<TabNav value="annotations_general">General</TabNav>
<TabNav value="annotations_border">Border</TabNav>
</TabList>
<TabContent value="annotations_general">
<FormItem
label="Tooltip Enabled"
invalid={errors.tooltipEnabled && touched.tooltipEnabled}
errorMessage={errors.tooltipEnabled}
>
<Field name="tooltipEnabled" component={Checkbox} />
</FormItem>
<FormItem
label="Type"
invalid={errors.type && touched.type}
errorMessage={errors.type}
>
<Field type="text" name="type">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
options={chartAnnotationTypeListOptions}
isClearable={true}
value={chartAnnotationTypeListOptions.filter(
(option) => option.value === values.type,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Series"
invalid={errors.series && touched.series}
errorMessage={errors.series}
>
<Field type="text" name="type">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
options={SeriesList()}
isClearable={true}
value={SeriesList()?.find((option) => option.value === values.series)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Name"
invalid={errors.name && touched.name}
errorMessage={errors.name}
>
<Field type="text" name="name" component={Input} />
</FormItem>
<FormItem
label="Text"
invalid={errors.text && touched.text}
errorMessage={errors.text}
>
<Field type="text" name="text" component={Input} />
</FormItem>
<FormItem
label="Value"
invalid={errors.value && touched.value}
errorMessage={errors.value}
>
<Field type="text" name="value" component={Input} />
</FormItem>
<FormItem
label="Argument"
invalid={errors.argument && touched.argument}
errorMessage={errors.argument}
>
<Field name="argument" component={Input} />
</FormItem>
<FormItem
label="Color"
invalid={errors.color && touched.color}
errorMessage={errors.color}
>
<Field type="text" name="color" component={Input} />
</FormItem>
<FormItem
label="Word Wrap"
invalid={errors.wordWrap && touched.wordWrap}
errorMessage={errors.wordWrap}
>
<Field type="text" name="wordWrap">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
options={chartTitleWordWrapListOptions}
isClearable={true}
value={chartTitleWordWrapListOptions.filter(
(option) => option.value === values.wordWrap,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Description"
invalid={errors.description && touched.description}
errorMessage={errors.description}
>
<Field type="text" name="description" component={Input} />
</FormItem>
<FormItem
label="Image"
invalid={errors.image && touched.image}
errorMessage={errors.image}
>
<Field type="text" name="image" component={Input} />
</FormItem>
<FormItem
label="Width"
invalid={errors.width && touched.width}
errorMessage={errors.width}
>
<Field type="number" name="width" component={Input} />
</FormItem>
<FormItem
label="Height"
invalid={errors.height && touched.height}
errorMessage={errors.height}
>
<Field type="number" name="height" component={Input} />
</FormItem>
<FormItem
label="Padding Left/Right"
invalid={errors.paddingLeftRight && touched.paddingLeftRight}
errorMessage={errors.paddingLeftRight}
>
<Field type="number" name="paddingLeftRight" component={Input} />
</FormItem>
<FormItem
label="Padding Top/Bottom"
invalid={errors.paddingTopBottom && touched.paddingTopBottom}
errorMessage={errors.paddingTopBottom}
>
<Field type="number" name="paddingTopBottom" component={Input} />
</FormItem>
<FormItem label="X" invalid={errors.x && touched.x} errorMessage={errors.x}>
<Field type="number" name="x" component={Input} />
</FormItem>
<FormItem label="Y" invalid={errors.y && touched.y} errorMessage={errors.y}>
<Field type="number" name="y" component={Input} />
</FormItem>
<FormItem
label="OffsetX"
invalid={errors.offsetX && touched.offsetX}
errorMessage={errors.offsetX}
>
<Field type="number" name="offsetX" component={Input} />
</FormItem>
<FormItem
label="OffsetY"
invalid={errors.offsetY && touched.offsetY}
errorMessage={errors.offsetY}
>
<Field type="number" name="offsetY" component={Input} />
</FormItem>
</TabContent>
<TabContent value="annotations_border">
<FormItem
label="Visible"
invalid={errors.border?.visible && touched.border?.visible}
errorMessage={errors.border?.visible}
>
<Field name="border.visible" component={Checkbox} />
</FormItem>
<FormItem
label="Color"
invalid={errors.border?.color && touched.border?.color}
errorMessage={errors.border?.color}
>
<Field type="text" name="border.color" component={Input} />
</FormItem>
<FormItem
label="Dash Style"
invalid={errors.border?.dashStyle && touched.border?.dashStyle}
errorMessage={errors.border?.dashStyle}
>
<Field type="text" name="border.dashStyle">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
options={chartSeriesDashStyleOptions}
isClearable={true}
value={chartSeriesDashStyleOptions.filter(
(option) => option.value === values.border.dashStyle,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Width"
invalid={errors.border?.width && touched.border?.width}
errorMessage={errors.border?.width}
>
<Field type="number" name="border.width" component={Input} />
</FormItem>
</TabContent>
</Tabs>
</div>
<div className="text-right mt-4">
<Button block variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
</Button>
</div>
</FormContainer>
</Form>
)}
</Formik>
</Dialog>
<Dialog
id="confirmDelete"
isOpen={confirmDelete.isOpen}
onClose={() => setConfirmDelete(defaultConfirmDelete)}
onRequestClose={() => setConfirmDelete(defaultConfirmDelete)}
>
<h5 className="mb-4">Delete</h5>
<p>Silmek istediğinize emin misiniz?</p>
<div className="text-right mt-6">
<Button
className="ltr:mr-2 rtl:ml-2"
variant="plain"
onClick={() => {
setConfirmDelete(defaultConfirmDelete)
}}
>
Cancel
</Button>
<Button
variant="solid"
onClick={async () => {
if (chartCode == null) return
await deleteChartJsonItem(
confirmDelete.id,
chartCode,
confirmDelete.index,
confirmDelete.fieldName,
)
toast.push(
<Notification type="success" duration={2000}>
{translate('::ListForms.KayitSilindi')}
</Notification>,
{
placement: 'top-end',
2025-05-06 06:45:49 +00:00
},
)
getChartValues()
setConfirmDelete(defaultConfirmDelete)
}}
>
Delete
</Button>
</div>
</Dialog>
2025-08-15 13:42:27 +00:00
</Container>
2025-05-06 06:45:49 +00:00
) : (
<></>
)
}
export default ChartEdit