@catalystlabs/awm
Version:
Appwrite Migration Tool - Schema management and code generation for Appwrite databases
193 lines (175 loc) • 5.61 kB
JavaScript
'use client';
import { useState } from 'react';
import { Modal, Button, Form, Input, InputNumber, DatePicker, Toggle, Message, toaster } from 'rsuite';
export default function CreateDocumentModal({ collection, open, onClose, onSuccess }) {
const [formValue, setFormValue] = useState({});
const [loading, setLoading] = useState(false);
async function handleCreate() {
try {
setLoading(true);
// Validate required fields
const requiredFields = collection.attributes.filter(attr => attr.required);
for (const field of requiredFields) {
if (!formValue[field.key]) {
toaster.push(
<Message showIcon type="error" closable>
{field.key} is required
</Message>,
{ placement: 'topEnd', duration: 3000 }
);
return;
}
}
const response = await fetch(`/api/collections/${collection.$id}/documents`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data: formValue })
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Failed to create document');
}
toaster.push(
<Message showIcon type="success" closable>
Document created successfully
</Message>,
{ placement: 'topEnd', duration: 3000 }
);
setFormValue({});
onSuccess();
} catch (err) {
toaster.push(
<Message showIcon type="error" closable>
{err.message}
</Message>,
{ placement: 'topEnd', duration: 5000 }
);
} finally {
setLoading(false);
}
}
function renderField(attribute) {
const { key, type, required, array } = attribute;
const commonProps = {
name: key,
placeholder: `Enter ${key}${array ? ' (comma separated)' : ''}`,
value: formValue[key] || '',
onChange: (value) => {
setFormValue(prev => ({ ...prev, [key]: value }));
}
};
switch (type) {
case 'string':
case 'email':
case 'url':
return (
<Form.Group controlId={key}>
<Form.ControlLabel>
{key} {required && <span style={{ color: 'red' }}>*</span>}
</Form.ControlLabel>
<Input {...commonProps} />
{array && <Form.HelpText>Enter values separated by commas</Form.HelpText>}
</Form.Group>
);
case 'integer':
return (
<Form.Group controlId={key}>
<Form.ControlLabel>
{key} {required && <span style={{ color: 'red' }}>*</span>}
</Form.ControlLabel>
<InputNumber
{...commonProps}
step={1}
onChange={(value) => {
setFormValue(prev => ({ ...prev, [key]: value }));
}}
/>
</Form.Group>
);
case 'float':
return (
<Form.Group controlId={key}>
<Form.ControlLabel>
{key} {required && <span style={{ color: 'red' }}>*</span>}
</Form.ControlLabel>
<InputNumber
{...commonProps}
step={0.01}
onChange={(value) => {
setFormValue(prev => ({ ...prev, [key]: value }));
}}
/>
</Form.Group>
);
case 'boolean':
return (
<Form.Group controlId={key}>
<Form.ControlLabel>
{key} {required && <span style={{ color: 'red' }}>*</span>}
</Form.ControlLabel>
<Toggle
checked={formValue[key] || false}
onChange={(checked) => {
setFormValue(prev => ({ ...prev, [key]: checked }));
}}
/>
</Form.Group>
);
case 'datetime':
return (
<Form.Group controlId={key}>
<Form.ControlLabel>
{key} {required && <span style={{ color: 'red' }}>*</span>}
</Form.ControlLabel>
<DatePicker
format="yyyy-MM-dd HH:mm:ss"
value={formValue[key] ? new Date(formValue[key]) : null}
onChange={(date) => {
setFormValue(prev => ({ ...prev, [key]: date ? date.toISOString() : null }));
}}
style={{ width: '100%' }}
/>
</Form.Group>
);
default:
return (
<Form.Group controlId={key}>
<Form.ControlLabel>
{key} {required && <span style={{ color: 'red' }}>*</span>}
</Form.ControlLabel>
<Input {...commonProps} as="textarea" rows={3} />
<Form.HelpText>Type: {type}</Form.HelpText>
</Form.Group>
);
}
}
return (
<Modal
open={open}
onClose={onClose}
size="md"
overflow={true}
>
<Modal.Header>
<Modal.Title>Create New Document</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form fluid formValue={formValue}>
{collection?.attributes.map((attr) => (
<div key={attr.key} style={{ marginBottom: '16px' }}>
{renderField(attr)}
</div>
))}
</Form>
</Modal.Body>
<Modal.Footer>
<Button onClick={onClose} appearance="subtle" disabled={loading}>
Cancel
</Button>
<Button onClick={handleCreate} appearance="primary" loading={loading}>
Create
</Button>
</Modal.Footer>
</Modal>
);
}