Chart Drawer
This commit is contained in:
parent
01ad6ffa60
commit
5d7db888ec
2 changed files with 62 additions and 54 deletions
|
|
@ -247,29 +247,29 @@ export const chartPaletteExtensionModeOptions = [
|
|||
]
|
||||
|
||||
export const chartSeriesTypeOptions = [
|
||||
{ value: 'line', label: 'Line' },
|
||||
{ value: 'stepline', label: 'Stepline' },
|
||||
{ value: 'bar', label: 'Bar' },
|
||||
{ value: 'fullstackedbar', label: 'Fullstackedbar' },
|
||||
{ value: 'rangebar', label: 'Rangebar' },
|
||||
{ value: 'rangearea', label: 'Rangearea' },
|
||||
{ value: 'fullstackedarea', label: 'Fullstackedarea' },
|
||||
{ value: 'area', label: 'Area' },
|
||||
{ value: 'bubble', label: 'Bubble' },
|
||||
{ value: 'candlestick', label: 'Candlestick' },
|
||||
{ value: 'fullstackedline', label: 'Fullstackedline' },
|
||||
{ value: 'fullstackedspline', label: 'Fullstackedspline' },
|
||||
{ value: 'fullstackedsplinearea', label: 'Fullstackedsplinearea' },
|
||||
{ value: 'scatter', label: 'Scatter' },
|
||||
{ value: 'spline', label: 'Spline' },
|
||||
{ value: 'splinearea', label: 'Splinearea' },
|
||||
{ value: 'stackedarea', label: 'Stackedarea' },
|
||||
{ value: 'stackedbar', label: 'Stackedbar' },
|
||||
{ value: 'stackedline', label: 'Stackedline' },
|
||||
{ value: 'stackedspline', label: 'Stackedspline' },
|
||||
{ value: 'stackedsplinearea', label: 'Stackedsplinearea' },
|
||||
{ value: 'steparea', label: 'Steparea' },
|
||||
{ value: 'stock', label: 'Stock' },
|
||||
{ value: 'line', label: 'Line', icon: '📈' },
|
||||
{ value: 'stepline', label: 'Stepline', icon: '📉' },
|
||||
{ value: 'bar', label: 'Bar', icon: '📊' },
|
||||
{ value: 'fullstackedbar', label: 'Fullstacked Bar', icon: '📚' },
|
||||
{ value: 'rangebar', label: 'Range Bar', icon: '📐' },
|
||||
{ value: 'rangearea', label: 'Range Area', icon: '🗺️' },
|
||||
{ value: 'fullstackedarea', label: 'Fullstacked Area', icon: '⛰️' },
|
||||
{ value: 'area', label: 'Area', icon: '🏔️' },
|
||||
{ value: 'bubble', label: 'Bubble', icon: '🫧' },
|
||||
{ value: 'candlestick', label: 'Candlestick', icon: '🕯️' },
|
||||
{ value: 'fullstackedline', label: 'Fullstacked Line', icon: '📶' },
|
||||
{ value: 'fullstackedspline', label: 'Fullstacked Spline', icon: '〰️📶' },
|
||||
{ value: 'fullstackedsplinearea', label: 'Fullstacked Spline Area', icon: '⛰️〰' },
|
||||
{ value: 'scatter', label: 'Scatter', icon: '🔵' },
|
||||
{ value: 'spline', label: 'Spline', icon: '〰️' },
|
||||
{ value: 'splinearea', label: 'Spline Area', icon: '🌄' },
|
||||
{ value: 'stackedarea', label: 'Stacked Area', icon: '🧱⛰️' },
|
||||
{ value: 'stackedbar', label: 'Stacked Bar', icon: '🧱📊' },
|
||||
{ value: 'stackedline', label: 'Stacked Line', icon: '🧱📈' },
|
||||
{ value: 'stackedspline', label: 'Stacked Spline', icon: '🧱〰️' },
|
||||
{ value: 'stackedsplinearea', label: 'Stacked Spline Area', icon: '🧱🌄' },
|
||||
{ value: 'steparea', label: 'Step Area', icon: '🪜' },
|
||||
{ value: 'stock', label: 'Stock', icon: '💹' },
|
||||
]
|
||||
|
||||
export const chartSeriesSelectionModeOptions = [
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Button, FormContainer, Input, Notification, Select, toast } from '@/com
|
|||
import { Field, FieldArray, Form, Formik, FieldProps } from 'formik'
|
||||
import { FaMinus, FaPlus, FaTimes, FaSave } from 'react-icons/fa'
|
||||
import { SelectBoxOption } from '@/types/shared'
|
||||
import { columnSummaryTypeListOptions } from '../admin/listForm/edit/options'
|
||||
import { chartSeriesTypeOptions, columnSummaryTypeListOptions } from '../admin/listForm/edit/options'
|
||||
import { ChartSeriesDto } from '@/proxy/admin/charts/models'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { useStoreState } from '@/store/store'
|
||||
|
|
@ -35,24 +35,15 @@ const ChartDrawer = ({
|
|||
series: array().of(
|
||||
object().shape({
|
||||
name: string().required(translate('::App.Platform.ChartDrawer.NameRequired')),
|
||||
argumentField: string().required(translate('::App.Platform.ChartDrawer.ArgumentFieldRequired')),
|
||||
argumentField: string().required(
|
||||
translate('::App.Platform.ChartDrawer.ArgumentFieldRequired'),
|
||||
),
|
||||
valueField: string().required(translate('::App.Platform.ChartDrawer.ValueFieldRequired')),
|
||||
summaryType: string().required(translate('::App.Platform.ChartDrawer.SummaryTypeRequired')),
|
||||
}),
|
||||
),
|
||||
})
|
||||
|
||||
// Chart type icons
|
||||
const chartTypeIcons = [
|
||||
{ type: 'line', label: 'Line', icon: '📈' },
|
||||
{ type: 'bar', label: 'Bar', icon: '📊' },
|
||||
{ type: 'area', label: 'Area', icon: '🏔️' },
|
||||
{ type: 'scatter', label: 'Scatter', icon: '🔵' },
|
||||
{ type: 'spline', label: 'Spline', icon: '〰️' },
|
||||
{ type: 'stackedbar', label: 'Stacked Bar', icon: '📚' },
|
||||
{ type: 'stackedarea', label: 'Stacked Area', icon: '⛰️' },
|
||||
]
|
||||
|
||||
const newSeriesValue = () => {
|
||||
return {
|
||||
index: -1,
|
||||
|
|
@ -111,9 +102,14 @@ const ChartDrawer = ({
|
|||
onSubmit={async (values, { setSubmitting }) => {
|
||||
try {
|
||||
await onSave(values.series)
|
||||
toast.push(<Notification type="success">{translate('::App.Platform.ChartDrawer.ChartSaved')}</Notification>, {
|
||||
toast.push(
|
||||
<Notification type="success">
|
||||
{translate('::App.Platform.ChartDrawer.ChartSaved')}
|
||||
</Notification>,
|
||||
{
|
||||
placement: 'top-end',
|
||||
})
|
||||
},
|
||||
)
|
||||
onClose()
|
||||
} catch (error: any) {
|
||||
toast.push(
|
||||
|
|
@ -186,7 +182,9 @@ const ChartDrawer = ({
|
|||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<span className="font-semibold text-sm">{translate('::App.Platform.ChartDrawer.Series')} #{index + 1}</span>
|
||||
<span className="font-semibold text-sm">
|
||||
{translate('::App.Platform.ChartDrawer.Series')} #{index + 1}
|
||||
</span>
|
||||
<Button
|
||||
type="button"
|
||||
size="xs"
|
||||
|
|
@ -201,7 +199,9 @@ const ChartDrawer = ({
|
|||
|
||||
{/* Chart Type Selector */}
|
||||
<div className="mb-3">
|
||||
<label className="text-xs font-medium mb-1 block">{translate('::App.Platform.ChartDrawer.ChartType')}</label>
|
||||
<label className="text-xs font-medium mb-1 block">
|
||||
{translate('::App.Platform.ChartDrawer.ChartType')}
|
||||
</label>
|
||||
<Field name={`series[${index}].type`}>
|
||||
{({ field, form }: FieldProps) => (
|
||||
<div className="relative">
|
||||
|
|
@ -215,33 +215,33 @@ const ChartDrawer = ({
|
|||
className="w-full px-3 py-2 text-left border rounded hover:bg-white flex items-center gap-2 transition-colors"
|
||||
>
|
||||
<span className="text-xl">
|
||||
{chartTypeIcons.find((t) => t.type === field.value)
|
||||
{chartSeriesTypeOptions.find((t) => t.label === field.value)
|
||||
?.icon || '📊'}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{chartTypeIcons.find((t) => t.type === field.value)
|
||||
{chartSeriesTypeOptions.find((t) => t.label === field.value)
|
||||
?.label || field.value}
|
||||
</span>
|
||||
</button>
|
||||
{selectedSeriesIndex === index && (
|
||||
<div className="absolute z-50 mt-1 w-full bg-white border rounded-lg shadow-xl p-2">
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{chartTypeIcons.map((chartType) => (
|
||||
{chartSeriesTypeOptions.map((chartType) => (
|
||||
<button
|
||||
key={chartType.type}
|
||||
key={chartType.label}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
form.setFieldValue(field.name, chartType.type)
|
||||
form.setFieldValue(field.name, chartType.label)
|
||||
setSelectedSeriesIndex(-1)
|
||||
}}
|
||||
className={`p-3 rounded-lg hover:bg-blue-50 flex flex-col items-center gap-1 transition-all ${
|
||||
field.value === chartType.type
|
||||
className={`p-2 rounded-lg hover:bg-blue-50 flex items-center gap-2 transition-all ${
|
||||
field.value === chartType.label
|
||||
? 'bg-blue-100 ring-2 ring-blue-400'
|
||||
: 'bg-gray-50'
|
||||
}`}
|
||||
>
|
||||
<span className="text-2xl">{chartType.icon}</span>
|
||||
<span className="text-xs font-medium text-center">
|
||||
<span className="text-xl">{chartType.icon}</span>
|
||||
<span className="text-xs font-medium">
|
||||
{chartType.label}
|
||||
</span>
|
||||
</button>
|
||||
|
|
@ -256,7 +256,9 @@ const ChartDrawer = ({
|
|||
|
||||
{/* Name */}
|
||||
<div className="mb-3">
|
||||
<label className="text-xs font-medium mb-1 block">{translate('::App.Platform.ChartDrawer.Name')}</label>
|
||||
<label className="text-xs font-medium mb-1 block">
|
||||
{translate('::App.Platform.ChartDrawer.Name')}
|
||||
</label>
|
||||
<Field
|
||||
size="sm"
|
||||
name={`series[${index}].name`}
|
||||
|
|
@ -284,7 +286,9 @@ const ChartDrawer = ({
|
|||
onChange={(option) => {
|
||||
form.setFieldValue(field.name, option?.value)
|
||||
}}
|
||||
placeholder={translate('::App.Platform.ChartDrawer.SelectField')}
|
||||
placeholder={translate(
|
||||
'::App.Platform.ChartDrawer.SelectField',
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
|
|
@ -308,7 +312,9 @@ const ChartDrawer = ({
|
|||
onChange={(option) => {
|
||||
form.setFieldValue(field.name, option?.value)
|
||||
}}
|
||||
placeholder={translate('::App.Platform.ChartDrawer.SelectField')}
|
||||
placeholder={translate(
|
||||
'::App.Platform.ChartDrawer.SelectField',
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
|
|
@ -351,7 +357,9 @@ const ChartDrawer = ({
|
|||
<Button variant="solid" loading={isSubmitting} type="submit" className="flex-1">
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<FaSave />
|
||||
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::App.Platform.ChartDrawer.Save')}
|
||||
{isSubmitting
|
||||
? translate('::SavingWithThreeDot')
|
||||
: translate('::App.Platform.ChartDrawer.Save')}
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue