Files
Meeting_Assistant/frontend/src/pages/ActionItemPage.jsx
beabigegg 0fee703b84 back
2025-08-17 15:26:44 +08:00

174 lines
7.7 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import {
Box, Typography, Paper, CircularProgress, Alert,
TextField, Button, Select, MenuItem, FormControl, InputLabel, Grid, Link
} from '@mui/material';
import { getActionItemDetails, updateActionItem, uploadAttachment } from '../services/api';
const ActionItemPage = () => {
const { actionId } = useParams();
const navigate = useNavigate();
const [actionItem, setActionItem] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
const [isEditing, setIsEditing] = useState(false);
const [attachment, setAttachment] = useState(null);
useEffect(() => {
const fetchActionItem = async () => {
setLoading(true);
try {
const data = await getActionItemDetails(actionId);
setActionItem(data);
} catch (err) {
setError(err.message || 'Could not fetch action item details.');
} finally {
setLoading(false);
}
};
fetchActionItem();
}, [actionId]);
const handleUpdate = async () => {
if (!actionItem) return;
setLoading(true);
try {
// Only send fields that are meant to be updated
const updateData = {
item: actionItem.item,
action: actionItem.action,
status: actionItem.status,
due_date: actionItem.due_date,
// owner_id is typically not changed from this screen, but could be added if needed
};
await updateActionItem(actionId, updateData);
if (attachment) {
// Note: The backend needs an endpoint to handle attachment uploads for an action item.
// This is a placeholder for that functionality.
// await uploadAttachment(actionId, attachment);
console.warn("Attachment upload functionality is not yet implemented on the backend.");
}
setIsEditing(false);
// Refresh data after update
const data = await getActionItemDetails(actionId);
setActionItem(data);
} catch (err) {
setError(err.response?.data?.error || 'Failed to update action item.');
} finally {
setLoading(false);
}
};
const handleFileChange = (event) => {
setAttachment(event.target.files[0]);
};
if (loading) return <Box sx={{ display: 'flex', justifyContent: 'center', p: 4 }}><CircularProgress /></Box>;
if (error) return <Alert severity="error">{error}</Alert>;
if (!actionItem) return <Alert severity="info">No action item found.</Alert>;
return (
<Box sx={{ p: 3 }}>
<Typography variant="h4" gutterBottom>
Action Item for: {actionItem.meeting?.topic || 'General Task'}
</Typography>
<Paper sx={{ p: 3 }}>
<Grid container spacing={2}>
<Grid item xs={12}>
<TextField
label="Context/Item"
fullWidth
multiline
rows={2}
value={actionItem.item || ''}
onChange={(e) => setActionItem({ ...actionItem, item: e.target.value })}
InputProps={{ readOnly: !isEditing }}
variant={isEditing ? "outlined" : "filled"}
/>
</Grid>
<Grid item xs={12}>
<TextField
label="Action"
fullWidth
multiline
rows={4}
value={actionItem.action || ''}
onChange={(e) => setActionItem({ ...actionItem, action: e.target.value })}
InputProps={{ readOnly: !isEditing }}
variant={isEditing ? "outlined" : "filled"}
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormControl fullWidth variant={isEditing ? "outlined" : "filled"}>
<InputLabel>Status</InputLabel>
<Select
label="Status"
value={actionItem.status || 'pending'}
onChange={(e) => setActionItem({ ...actionItem, status: e.target.value })}
readOnly={!isEditing}
>
<MenuItem value="pending">Pending</MenuItem>
<MenuItem value="in_progress">In Progress</MenuItem>
<MenuItem value="completed">Completed</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
label="Due Date"
type="date"
fullWidth
value={actionItem.due_date || ''}
onChange={(e) => setActionItem({ ...actionItem, due_date: e.target.value })}
InputProps={{ readOnly: !isEditing }}
variant={isEditing ? "outlined" : "filled"}
InputLabelProps={{ shrink: true }}
/>
</Grid>
<Grid item xs={12}>
<Typography>Owner: {actionItem.owner?.username || 'N/A'}</Typography>
{actionItem.attachment_path && (
<Typography>
Attachment: <Link href={`/api/download/${actionItem.attachment_path.split('/').pop()}`} target="_blank" rel="noopener">Download</Link>
</Typography>
)}
</Grid>
{isEditing && (
<Grid item xs={12}>
<Button
variant="contained"
component="label"
>
Upload Attachment
<input
type="file"
hidden
onChange={handleFileChange}
/>
</Button>
{attachment && <Typography sx={{ display: 'inline', ml: 2 }}>{attachment.name}</Typography>}
</Grid>
)}
<Grid item xs={12} sx={{ mt: 2 }}>
{isEditing ? (
<Box>
<Button onClick={handleUpdate} variant="contained" color="primary" disabled={loading}>
{loading ? <CircularProgress size={24} /> : 'Save Changes'}
</Button>
<Button onClick={() => setIsEditing(false)} sx={{ ml: 2 }}>Cancel</Button>
</Box>
) : (
<Button onClick={() => setIsEditing(true)} variant="contained">Edit</Button>
)}
</Grid>
</Grid>
</Paper>
</Box>
);
};
export default ActionItemPage;