firecms
firecms copied to clipboard
Dynamic map
Is there way for dynamic map?
i want for example to add to "product" field of "members" the field will be map of userid to role {"adafewr324asfas":"admin}
Hi @dvird I am not totally sure what you mean
today we can only build a map with default keys
for example:
publisher: { title: "Publisher", description: "This is an example of a map property", dataType: "map", properties: { name: { title: "Name", dataType: "string" }, external_id: { title: "External id", dataType: "string" } } }
i want to put dynamic keys on the cms, i want the key will be user id , and value will be role
I have the same problem. I have a restaurant model restaurants:{ restaurantTables : Record<string, RestaurantTable>}
and I can't represent it in the CMS. because the CMS doesn't allow to define a property as a key
Hi guys, this feature is not planned in the near future. We are happy to receive PRs though, and if this is important for your business we are also happy to discuss implementing it as a consulting project, you can reach us at [email protected]
@fgatti675 I was able to work around this by creating a custom preview and a custom field. Editing, updating and adding work fine, except for deleting.
eg: const tables : Record<String, Table> = { 'tableId_1' : {name: 'Africa'}, 'tableId_2' : {name: 'Europe'}, 'tableId_3' : {name: 'Asia'}} ; delete the tables [tableId_3]; delete the tables [tableId_2];
.
we expect on the database tables: {'tableId_1': {name: 'Africa'}}
which is not the case. In fact, the database is not updated but when we print the values
contained onPreSave
and onSaveSuccess
callback function, they contain the correct information but the database is not updated and the preview widget contains this map tables: {'tableId_1': {name: 'Africa'}, 'tableId_2': {name: 'Europe'}}
Hi guys, it is now possible to add arbitrary key-value data to map properties, feed free to try out!
@warrenrhodes found solution for delete, care to share part of you code I am in same problem, thanks
@muhamed-didovic sorry to be late. with part of the code do you want actually?
There the field schema
restaurantTables: buildProperty<Record<string, unknown>>({
name: 'Restaurant Tables',
dataType: 'map',
validation: { required: false, unique: true },
Preview: RestaurantTablesPreView,
Field: RestaurantTablesFields,
}),
The RestaurantTablesPreView and RestaurantTablesFields code.
export function RestaurantTablesPreView({
value,
}: PropertyPreviewProps<Partial<Record<string, unknown>>>) {
const [open, setOpen] = React.useState(false);
const handleClickSetQrCode = (webDeepLink: string | undefined) => {
if (!webDeepLink) {
return;
}
window.open(
`https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl=${webDeepLink}`,
'_blank'
);
return;
};
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
if (!value) {
return <Box />;
}
const restaurantTables = value as Record<string, RestaurantTable>;
return (
<Box
sx={(theme) => ({
display: 'flex',
flexWrap: 'wrap',
gap: theme.spacing(0.5),
})}
>
<Button variant="outlined" onClick={handleClickOpen}>
DineIn Table
</Button>
<Dialog
fullWidth={true}
maxWidth={'lg'}
open={open}
onClose={handleClose}
>
<DialogContent>
<TableContainer sx={{ maxHeight: 440 }}>
<Table stickyHeader aria-label="sticky table">
<TableHead>
<TableRow>
{columns.map((column) => (
<TableCell key={column.id} align={'center'}>
{column.label}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{Object.entries(restaurantTables).map(([key, table]) => {
return (
<TableRow key={key}>
<TableCell>{table.dineInTable}</TableCell>
<TableCell align="center">
{table.dineInWebDeepLink}
</TableCell>
<TableCell align="center">
{table.dineInWebDeepLink ? (
<Button
variant="contained"
sx={{ marginY: '10px' }}
onClick={() =>
handleClickSetQrCode(table.dineInWebDeepLink)
}
>
Display QrCode
</Button>
) : (
<Box />
)}
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
</DialogContent>
</Dialog>
</Box>
);
}
export function RestaurantTablesFields({
value,
isSubmitting,
setValue,
showError,
error,
}: FieldProps<Partial<Record<string, unknown>>>) {
const [restaurantTable, setRestaurantTable] = useState<
Record<string, RestaurantTable> | undefined
>(value as Record<string, RestaurantTable> | undefined);
/**
* Adds a new dineIn table.
*/
const addNewDineInTable = () => {
setRestaurantTable({
...restaurantTable,
[generateUUID()]: {
dineInTable: '',
},
});
};
/**
* Updates a dineIn table.
*/
const updateDineInTable = (value: string, tableKey: string) => {
if (!restaurantTable) return;
restaurantTable[tableKey].dineInTable = value;
};
/**
* Updates the restaurant table on submitting.
* @returns { void }.
*/
const updateRestaurantTable = useCallback(async () => {
if (restaurantTable) {
const restaurantTables = Object.values(restaurantTable);
for (let i = 0; i < restaurantTables.length; i++) {
const name = restaurantTables[i].dineInTable;
if (!name || name.trim().length === 0) {
return;
}
for (let j = i + 1; j < restaurantTables.length; j++) {
if (
restaurantTables[i].dineInTable === restaurantTables[j].dineInTable
) {
return;
}
}
}
setValue(
restaurantTable && Object.values(restaurantTable).length !== 0
? restaurantTable
: null
);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [restaurantTable]);
useEffect(() => {
if (isSubmitting) {
updateRestaurantTable();
}
}, [isSubmitting, updateRestaurantTable]);
return (
<Paper variant="outlined" sx={{ width: '100%', padding: '12px' }}>
<List sx={{ width: '100%', bgcolor: 'background.paper' }}>
{restaurantTable ? (
Object.entries(restaurantTable).map(([key, value]) => {
return (
<Card
sx={{
margin: '10px',
padding: '10px',
}}
>
<Stack direction={'row'} alignItems={'center'}>
<FormControl error={!!error}>
<TextField
key={value.dineInTable}
id="outlined-basic"
label="Table Name"
variant="outlined"
defaultValue={value.dineInTable}
required
onChange={(value) =>
updateDineInTable(value.target.value, key)
}
/>
{showError && <FormHelperText>{error}</FormHelperText>}
</FormControl>
</Stack>
</Card>
);
})
) : (
<Box />
)}
</List>
<Button
variant="outlined"
color="primary"
size="medium"
startIcon={<AddIcon />}
onClick={addNewDineInTable}
>
Add
</Button>
</Paper>
);
}
I hope this will help you.