diff --git a/backend/app/models.py b/backend/app/models.py index f58df52..cedd5c4 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -8,6 +8,7 @@ class Project(db.Model): name = db.Column(db.String(200), nullable=False) color = db.Column(db.String(7), nullable=False, default='#C9A84C') description = db.Column(db.Text) + drive_url = db.Column(db.String(500)) created_at = db.Column(db.DateTime, default=datetime.utcnow) deliverables = db.relationship( @@ -21,6 +22,7 @@ class Project(db.Model): 'name': self.name, 'color': self.color, 'description': self.description, + 'drive_url': self.drive_url, 'created_at': self.created_at.isoformat() if self.created_at else None, } if include_deliverables: diff --git a/backend/app/routes/projects.py b/backend/app/routes/projects.py index 159394d..e59a7ec 100644 --- a/backend/app/routes/projects.py +++ b/backend/app/routes/projects.py @@ -22,6 +22,7 @@ def create_project(): name=data['name'], color=data.get('color', '#C9A84C'), description=data.get('description', ''), + drive_url=data.get('drive_url', ''), ) db.session.add(project) db.session.flush() @@ -40,7 +41,7 @@ def create_project(): def update_project(id): project = Project.query.get_or_404(id) data = request.get_json() - for field in ('name', 'color', 'description'): + for field in ('name', 'color', 'description', 'drive_url'): if field in data: setattr(project, field, data[field]) db.session.commit() diff --git a/frontend/src/components/Projects/ProjectCard.jsx b/frontend/src/components/Projects/ProjectCard.jsx index 4711351..baa42d9 100644 --- a/frontend/src/components/Projects/ProjectCard.jsx +++ b/frontend/src/components/Projects/ProjectCard.jsx @@ -2,25 +2,57 @@ import Badge from '../UI/Badge' import { formatDate } from '../../utils/dateHelpers' import useFocusStore from '../../store/useFocusStore' +function DriveIcon() { + return ( + + + + + + + + + ) +} + export default function ProjectCard({ project, onEdit, onDelete }) { const openFocus = useFocusStore(s => s.openFocus) + return (
-
+ + {/* Header row */} +
{project.name}
-
+
+ {project.drive_url && ( + e.stopPropagation()} + className="flex items-center gap-1 text-[10px] text-text-muted hover:text-text-primary bg-surface hover:bg-surface-border/40 border border-surface-border hover:border-gold/30 rounded px-1.5 py-1 transition-all mr-1" + > + + Drive + + )}
+ {project.description && (

{project.description}

)} + + {/* Deliverable rows */}
{(project.deliverables || []).map(d => (
+
) diff --git a/frontend/src/components/Projects/ProjectModal.jsx b/frontend/src/components/Projects/ProjectModal.jsx index faff17d..a2936ed 100644 --- a/frontend/src/components/Projects/ProjectModal.jsx +++ b/frontend/src/components/Projects/ProjectModal.jsx @@ -13,6 +13,7 @@ export default function ProjectModal({ isOpen, onClose, project }) { const [name, setName] = useState('') const [desc, setDesc] = useState('') const [color, setColor] = useState('#4A90D9') + const [driveUrl, setDriveUrl] = useState('') const [rows, setRows] = useState([emptyRow()]) const [saving, setSaving] = useState(false) const isEditing = !!project @@ -22,11 +23,12 @@ export default function ProjectModal({ isOpen, onClose, project }) { setName(project.name || '') setDesc(project.description || '') setColor(project.color || '#4A90D9') + setDriveUrl(project.drive_url || '') setRows(project.deliverables?.length ? project.deliverables.map(d => ({ id: d.id, title: d.title, due_date: d.due_date?.substring(0,10)||'', status: d.status })) : [emptyRow()]) } else { - setName(''); setDesc(''); setColor('#4A90D9'); setRows([emptyRow()]) + setName(''); setDesc(''); setColor('#4A90D9'); setDriveUrl(''); setRows([emptyRow()]) } }, [project, isOpen]) @@ -37,11 +39,11 @@ export default function ProjectModal({ isOpen, onClose, project }) { setSaving(true) try { if (isEditing) { - const updated = await updateProject(project.id, { name, description: desc, color }) + const updated = await updateProject(project.id, { name, description: desc, color, drive_url: driveUrl }) storeUpdate({ ...updated, deliverables: project.deliverables }) } else { const valid = rows.filter(r => r.title.trim() && r.due_date) - const created = await createProject({ name, description: desc, color, deliverables: valid }) + const created = await createProject({ name, description: desc, color, drive_url: driveUrl, deliverables: valid }) addProject(created) } onClose() @@ -51,16 +53,44 @@ export default function ProjectModal({ isOpen, onClose, project }) { return (
+
setName(e.target.value)} placeholder="e.g. CODA" />
+