Chart Series değişikliği
This commit is contained in:
parent
e1e731a031
commit
ae9ce38478
2 changed files with 188 additions and 8 deletions
|
|
@ -32,8 +32,6 @@ import {
|
|||
columnSummaryTypeListOptions,
|
||||
} from '../options'
|
||||
import { ChartPanesDto, ChartSeriesDto, ChartValueAxisDto } from '@/proxy/admin/charts/models'
|
||||
import { getListFormFields } from '@/services/admin/list-form-field.service'
|
||||
import { groupBy } from 'lodash'
|
||||
import CreatableSelect from 'react-select/creatable'
|
||||
|
||||
const schema = object().shape({
|
||||
|
|
|
|||
|
|
@ -4,17 +4,20 @@ import { Container } from '@/components/shared'
|
|||
import { DX_CLASSNAMES } from '@/constants/app.constant'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import DxChart from 'devextreme-react/chart'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { Helmet } from 'react-helmet'
|
||||
import { useParams, useSearchParams } from 'react-router-dom'
|
||||
import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource'
|
||||
import { GridDto } from '@/proxy/form/models'
|
||||
import { usePermission } from '@/utils/hooks/usePermission'
|
||||
import { Button } from '@/components/ui'
|
||||
import { Button, FormContainer, FormItem, Input, toast, Notification, Dialog } from '@/components/ui'
|
||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||
import { usePWA } from '@/utils/hooks/usePWA'
|
||||
import { FaCog, FaSearch, FaSyncAlt } from 'react-icons/fa'
|
||||
import { FaCog, FaCrosshairs, FaMinus, FaPlus, FaSearch, FaSyncAlt } from 'react-icons/fa'
|
||||
import { buildSeriesDto } from './Utils'
|
||||
import { ChartSeriesDto } from '@/proxy/admin/charts/models'
|
||||
import { Formik, Form, Field, FieldArray, useFormikContext } from 'formik' // sadece buradan Form
|
||||
import { object, string, array } from 'yup'
|
||||
|
||||
interface ChartProps extends CommonProps, Meta {
|
||||
listFormCode: string
|
||||
|
|
@ -31,6 +34,8 @@ const Chart = (props: ChartProps) => {
|
|||
const { translate } = useLocalization()
|
||||
const { checkPermission } = usePermission()
|
||||
const isPwaMode = usePWA()
|
||||
const [series, setSeries] = useState<ChartSeriesDto[]>([])
|
||||
const initialized = useRef(false)
|
||||
|
||||
const [searchParams] = useSearchParams()
|
||||
const [chartOptions, setChartOptions] = useState<any>()
|
||||
|
|
@ -45,11 +50,27 @@ const Chart = (props: ChartProps) => {
|
|||
searchParams ? new URLSearchParams(searchParams) : new URLSearchParams(),
|
||||
)
|
||||
|
||||
const schema = object().shape({
|
||||
series: array().of(
|
||||
object().shape({
|
||||
name: string().required('Name Required'),
|
||||
argumentField: string().required('Argument Field Required'),
|
||||
valueField: string().required('Value Field Required'),
|
||||
summaryType: string().required('Summary Type Required'),
|
||||
}),
|
||||
),
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (!gridDto) return
|
||||
|
||||
const gridOptions = {
|
||||
...gridDto.gridOptions,
|
||||
seriesDto: series ?? gridDto.gridOptions.seriesDto,
|
||||
}
|
||||
|
||||
const dataSource = createSelectDataSource(
|
||||
gridDto.gridOptions,
|
||||
gridOptions,
|
||||
listFormCode,
|
||||
urlSearchParams,
|
||||
[],
|
||||
|
|
@ -85,7 +106,7 @@ const Chart = (props: ChartProps) => {
|
|||
valueAxis: gridDto.gridOptions.valueAxisDto,
|
||||
tooltip: gridDto.gridOptions.tooltipDto,
|
||||
|
||||
series: buildSeriesDto(gridDto.gridOptions.seriesDto),
|
||||
series: buildSeriesDto(series ?? gridDto.gridOptions.seriesDto),
|
||||
|
||||
panes: gridDto.gridOptions.panesDto?.length > 0 ? gridDto.gridOptions.panesDto : undefined,
|
||||
commonSeriesSettings: gridDto.gridOptions.commonSeriesSettingsDto,
|
||||
|
|
@ -100,7 +121,7 @@ const Chart = (props: ChartProps) => {
|
|||
}
|
||||
|
||||
setChartOptions(options)
|
||||
}, [gridDto, searchParams, urlSearchParams])
|
||||
}, [gridDto, series, searchParams, urlSearchParams])
|
||||
|
||||
const onFilter = useCallback(
|
||||
(value?: string) => {
|
||||
|
|
@ -148,6 +169,51 @@ const Chart = (props: ChartProps) => {
|
|||
[gridDto, urlSearchParams, searchText],
|
||||
)
|
||||
|
||||
const newSeriesValue = () => {
|
||||
return {
|
||||
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: true,
|
||||
backgroundColor: '#f05b41',
|
||||
customizeText: '',
|
||||
format: 'decimal',
|
||||
font: {
|
||||
color: '#FFFFFF',
|
||||
family: '"Segoe UI", "Helvetica Neue", "Trebuchet MS", Verdana, sans-serif',
|
||||
size: 12,
|
||||
weight: 400,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (gridDto && !initialized.current) {
|
||||
setSeries(gridDto.gridOptions.seriesDto)
|
||||
initialized.current = true
|
||||
}
|
||||
}, [gridDto])
|
||||
|
||||
const [openDialog, setOpenDialog] = useState(false)
|
||||
|
||||
return (
|
||||
<Container className={DX_CLASSNAMES}>
|
||||
{!isSubForm && gridDto && (
|
||||
|
|
@ -192,12 +258,24 @@ const Chart = (props: ChartProps) => {
|
|||
variant={'default'}
|
||||
className="text-sm"
|
||||
onClick={async () => {
|
||||
setSeries(gridDto?.gridOptions?.seriesDto ?? [])
|
||||
await props.refreshGridDto()
|
||||
}}
|
||||
title="Refresh Data"
|
||||
>
|
||||
<FaSyncAlt className="w-3 h-3" />
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
size="xs"
|
||||
variant="default"
|
||||
className="text-sm"
|
||||
onClick={() => setOpenDialog(true)}
|
||||
title="Edit Series"
|
||||
>
|
||||
<FaCrosshairs className="w-3 h-3" />
|
||||
</Button>
|
||||
|
||||
{checkPermission(gridDto?.gridOptions.permissionDto.u) && (
|
||||
<Button
|
||||
size="xs"
|
||||
|
|
@ -220,6 +298,110 @@ const Chart = (props: ChartProps) => {
|
|||
</div>
|
||||
</div>
|
||||
<DxChart key={'DxChart' + _listFormCode} {...chartOptions}></DxChart>
|
||||
|
||||
<Dialog isOpen={openDialog} onClose={() => setOpenDialog(false)} width={600}>
|
||||
<Formik
|
||||
enableReinitialize
|
||||
initialValues={{
|
||||
series: series && series.length > 0 ? series : [newSeriesValue()],
|
||||
}}
|
||||
validationSchema={schema}
|
||||
onSubmit={(values, { setSubmitting }) => {
|
||||
setSeries(values.series)
|
||||
|
||||
setSubmitting(true)
|
||||
try {
|
||||
toast.push(<Notification type="success">{'Chart güncellendi'}</Notification>, {
|
||||
placement: 'top-end',
|
||||
})
|
||||
setOpenDialog(false) // kaydettikten sonra dialogu kapat
|
||||
} catch (error: any) {
|
||||
toast.push(
|
||||
<Notification type="danger">
|
||||
Hata
|
||||
<code>{error}</code>
|
||||
</Notification>,
|
||||
{ placement: 'top-end' },
|
||||
)
|
||||
} finally {
|
||||
setSubmitting(false)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({ setFieldValue, values, isSubmitting }) => (
|
||||
<Form className="flex flex-col h-full">
|
||||
<FormContainer size="sm" className="flex flex-col h-full">
|
||||
{/* Kaydırılabilir içerik */}
|
||||
<div className="flex-1 overflow-y-auto p-2">
|
||||
<FieldArray name="series">
|
||||
{({ remove }) => (
|
||||
<div>
|
||||
{values.series.map((_, index) => (
|
||||
<div key={index} className="mb-2 border-b pb-2">
|
||||
<FormItem label="Name">
|
||||
<Field
|
||||
name={`series[${index}].name`}
|
||||
type="text"
|
||||
component={Input}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="Argument Field">
|
||||
<Field
|
||||
name={`series[${index}].argumentField`}
|
||||
type="text"
|
||||
component={Input}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="Value Field">
|
||||
<Field
|
||||
name={`series[${index}].valueField`}
|
||||
type="text"
|
||||
component={Input}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="Summary Type">
|
||||
<Field
|
||||
name={`series[${index}].summaryType`}
|
||||
type="text"
|
||||
component={Input}
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<Button
|
||||
shape="circle"
|
||||
type="button"
|
||||
className="mt-2"
|
||||
size="xs"
|
||||
icon={<FaMinus />}
|
||||
onClick={() => remove(index)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</FieldArray>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="flex gap-2 mt-auto pt-2 border-t text-right">
|
||||
<Button
|
||||
variant="default"
|
||||
type="button"
|
||||
onClick={() =>
|
||||
setFieldValue('series', [...values.series, newSeriesValue()])
|
||||
}
|
||||
>
|
||||
<FaPlus />
|
||||
</Button>
|
||||
<Button block variant="solid" loading={isSubmitting} type="submit">
|
||||
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
|
||||
</Button>
|
||||
</div>
|
||||
</FormContainer>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</Dialog>
|
||||
</div>
|
||||
)}
|
||||
</Container>
|
||||
|
|
|
|||
Loading…
Reference in a new issue