communitas 0.2.6

A diagnostic chat application for the P2P Foundation network
Documentation
import React, { useState } from 'react'
import {
  Dialog,
  DialogTitle,
  DialogContent,
  DialogActions,
  TextField,
  Button,
  FormControl,
  InputLabel,
  Select,
  MenuItem,
  Box,
  Typography
} from '@mui/material'

interface CreateOrganizationDialogProps {
  open: boolean
  onClose: () => void
  onSubmit: (data: {
    name: string
    description?: string
    visibility: 'public' | 'private' | 'invite_only'
    initial_storage_gb: number
  }) => void
}

const CreateOrganizationDialog: React.FC<CreateOrganizationDialogProps> = ({
  open,
  onClose,
  onSubmit
}) => {
  const [formData, setFormData] = useState({
    name: '',
    description: '',
    visibility: 'private' as 'public' | 'private' | 'invite_only',
    initial_storage_gb: 10
  })

  const [errors, setErrors] = useState<Record<string, string>>({})

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault()
    
    // Validate form
    const newErrors: Record<string, string> = {}
    
    if (!formData.name.trim()) {
      newErrors.name = 'Organization name is required'
    } else if (formData.name.trim().length < 3) {
      newErrors.name = 'Organization name must be at least 3 characters'
    }
    
    if (formData.initial_storage_gb < 1) {
      newErrors.initial_storage_gb = 'Storage must be at least 1 GB'
    } else if (formData.initial_storage_gb > 1000) {
      newErrors.initial_storage_gb = 'Storage cannot exceed 1000 GB'
    }

    setErrors(newErrors)
    
    if (Object.keys(newErrors).length === 0) {
      onSubmit({
        name: formData.name.trim(),
        description: formData.description.trim() || undefined,
        visibility: formData.visibility,
        initial_storage_gb: formData.initial_storage_gb
      })
      handleClose()
    }
  }

  const handleClose = () => {
    setFormData({
      name: '',
      description: '',
      visibility: 'private',
      initial_storage_gb: 10
    })
    setErrors({})
    onClose()
  }

  const handleInputChange = (field: string) => (
    event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement> | any
  ) => {
    const value = event.target.value
    setFormData(prev => ({ ...prev, [field]: value }))
    
    // Clear error when user starts typing
    if (errors[field]) {
      setErrors(prev => ({ ...prev, [field]: '' }))
    }
  }

  return (
    <Dialog open={open} onClose={handleClose} maxWidth="sm" fullWidth>
      <form onSubmit={handleSubmit}>
        <DialogTitle>Create New Organization</DialogTitle>
        
        <DialogContent>
          <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3, pt: 1 }}>
            <TextField
              label="Organization Name"
              value={formData.name}
              onChange={handleInputChange('name')}
              error={!!errors.name}
              helperText={errors.name}
              required
              fullWidth
              placeholder="e.g., MaidSafe Foundation"
            />

            <TextField
              label="Description"
              value={formData.description}
              onChange={handleInputChange('description')}
              multiline
              rows={3}
              fullWidth
              placeholder="Brief description of your organization..."
            />

            <FormControl fullWidth>
              <InputLabel>Visibility</InputLabel>
              <Select
                value={formData.visibility}
                label="Visibility"
                onChange={handleInputChange('visibility')}
              >
                <MenuItem value="public">
                  <Box>
                    <Typography variant="body1">Public</Typography>
                    <Typography variant="caption" color="text.secondary">
                      Anyone can discover and request to join
                    </Typography>
                  </Box>
                </MenuItem>
                <MenuItem value="private">
                  <Box>
                    <Typography variant="body1">Private</Typography>
                    <Typography variant="caption" color="text.secondary">
                      Only visible to members, invite-only
                    </Typography>
                  </Box>
                </MenuItem>
                <MenuItem value="invite_only">
                  <Box>
                    <Typography variant="body1">Invite Only</Typography>
                    <Typography variant="caption" color="text.secondary">
                      Members can only be added by invitation
                    </Typography>
                  </Box>
                </MenuItem>
              </Select>
            </FormControl>

            <TextField
              label="Initial Storage (GB)"
              type="number"
              value={formData.initial_storage_gb}
              onChange={handleInputChange('initial_storage_gb')}
              error={!!errors.initial_storage_gb}
              helperText={errors.initial_storage_gb || 'Storage allocation for organization and projects'}
              inputProps={{ min: 1, max: 1000, step: 1 }}
              fullWidth
            />

            <Box sx={{ bgcolor: 'background.paper', p: 2, borderRadius: 1, border: 1, borderColor: 'divider' }}>
              <Typography variant="subtitle2" gutterBottom>
                What you'll get:
              </Typography>
              <Typography variant="body2" color="text.secondary">
                • Organization-wide file system with {formData.initial_storage_gb} GB storage
              </Typography>
              <Typography variant="body2" color="text.secondary">
                • Unlimited groups for team discussions
              </Typography>
              <Typography variant="body2" color="text.secondary">
                • Projects with dedicated file systems
              </Typography>
              <Typography variant="body2" color="text.secondary">
                • Role-based permissions and member management
              </Typography>
            </Box>
          </Box>
        </DialogContent>

        <DialogActions>
          <Button onClick={handleClose}>
            Cancel
          </Button>
          <Button type="submit" variant="contained">
            Create Organization
          </Button>
        </DialogActions>
      </form>
    </Dialog>
  )
}

export default CreateOrganizationDialog