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,
  Alert
} from '@mui/material'

interface InviteMemberDialogProps {
  open: boolean
  onClose: () => void
  onSubmit: (data: {
    address: string
    role: 'Admin' | 'Member' | 'Viewer' | 'Guest'
    message?: string
  }) => void
  entityType?: 'organization' | 'group' | 'project'
}

const InviteMemberDialog: React.FC<InviteMemberDialogProps> = ({
  open,
  onClose,
  onSubmit,
  entityType
}) => {
  const [formData, setFormData] = useState({
    address: '',
    role: 'Member' as 'Admin' | 'Member' | 'Viewer' | 'Guest',
    message: ''
  })

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

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault()
    
    // Validate form
    const newErrors: Record<string, string> = {}
    
    if (!formData.address.trim()) {
      newErrors.address = 'Member address is required'
    } else if (!/^[a-z]+\.[a-z]+\.[a-z]+\.[a-z]+$/i.test(formData.address.trim())) {
      newErrors.address = 'Please enter a valid four-word address (e.g., user.name.test.here)'
    }

    setErrors(newErrors)
    
    if (Object.keys(newErrors).length === 0) {
      onSubmit({
        address: formData.address.trim().toLowerCase(),
        role: formData.role,
        message: formData.message.trim() || undefined
      })
      handleClose()
    }
  }

  const handleClose = () => {
    setFormData({
      address: '',
      role: 'Member',
      message: ''
    })
    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]: '' }))
    }
  }

  const getRoleDescription = (role: string) => {
    switch (role) {
      case 'Admin':
        return 'Can manage settings, members, and all content'
      case 'Member':
        return 'Can create content and invite other members'
      case 'Viewer':
        return 'Can view content but not make changes'
      case 'Guest':
        return 'Limited read-only access'
      default:
        return ''
    }
  }

  const getEntityTypeText = () => {
    switch (entityType) {
      case 'organization':
        return 'organization'
      case 'group':
        return 'group'
      case 'project':
        return 'project'
      default:
        return 'entity'
    }
  }

  return (
    <Dialog open={open} onClose={handleClose} maxWidth="sm" fullWidth>
      <form onSubmit={handleSubmit}>
        <DialogTitle>
          Invite Member to {getEntityTypeText().charAt(0).toUpperCase() + getEntityTypeText().slice(1)}
        </DialogTitle>
        
        <DialogContent>
          <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3, pt: 1 }}>
            <Alert severity="info" sx={{ mb: 1 }}>
              Members will receive an invitation to join this {getEntityTypeText()}. They can accept or decline the invitation.
            </Alert>

            <TextField
              label="Four-Word Address"
              value={formData.address}
              onChange={handleInputChange('address')}
              error={!!errors.address}
              helperText={errors.address || 'Enter the four-word address of the person you want to invite'}
              required
              fullWidth
              placeholder="user.name.test.here"
            />

            <FormControl fullWidth>
              <InputLabel>Role</InputLabel>
              <Select
                value={formData.role}
                label="Role"
                onChange={handleInputChange('role')}
              >
                <MenuItem value="Admin">
                  <Box>
                    <Typography variant="body1">Admin</Typography>
                    <Typography variant="caption" color="text.secondary">
                      {getRoleDescription('Admin')}
                    </Typography>
                  </Box>
                </MenuItem>
                <MenuItem value="Member">
                  <Box>
                    <Typography variant="body1">Member</Typography>
                    <Typography variant="caption" color="text.secondary">
                      {getRoleDescription('Member')}
                    </Typography>
                  </Box>
                </MenuItem>
                <MenuItem value="Viewer">
                  <Box>
                    <Typography variant="body1">Viewer</Typography>
                    <Typography variant="caption" color="text.secondary">
                      {getRoleDescription('Viewer')}
                    </Typography>
                  </Box>
                </MenuItem>
                <MenuItem value="Guest">
                  <Box>
                    <Typography variant="body1">Guest</Typography>
                    <Typography variant="caption" color="text.secondary">
                      {getRoleDescription('Guest')}
                    </Typography>
                  </Box>
                </MenuItem>
              </Select>
            </FormControl>

            <TextField
              label="Invitation Message (Optional)"
              value={formData.message}
              onChange={handleInputChange('message')}
              multiline
              rows={3}
              fullWidth
              placeholder="Add a personal message to your invitation..."
            />

            {entityType === 'group' && (
              <Alert severity="info" variant="outlined">
                <Typography variant="body2">
                  <strong>Group Invitation:</strong> This member will be able to participate in group discussions. 
                  File sharing uses the parent organization's storage.
                </Typography>
              </Alert>
            )}

            {entityType === 'project' && (
              <Alert severity="success" variant="outlined">
                <Typography variant="body2">
                  <strong>Project Invitation:</strong> This member will get access to the project's 
                  dedicated file system and collaboration tools.
                </Typography>
              </Alert>
            )}

            {entityType === 'organization' && (
              <Alert severity="warning" variant="outlined">
                <Typography variant="body2">
                  <strong>Organization Invitation:</strong> This member will be able to access all 
                  public groups and can be invited to projects within the organization.
                </Typography>
              </Alert>
            )}
          </Box>
        </DialogContent>

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

export default InviteMemberDialog