diff --git a/backend/app/repositories/proof_repository.py b/backend/app/repositories/proof_repository.py index be121bb..9ac0f83 100755 --- a/backend/app/repositories/proof_repository.py +++ b/backend/app/repositories/proof_repository.py @@ -5,7 +5,7 @@ from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload -from app.models.models import Proof, ProofVersion +from app.models.models import Campaign, Proof, ProofVersion class ProofRepository: @@ -198,9 +198,17 @@ class ProofRepository: latest_version = await self.get_latest_version_number(proof.id) new_version_number = latest_version + 1 - # Generate workfront ID + # Get campaign's workfront_id to use as base for proof workfront IDs + campaign_result = await self.session.execute( + select(Campaign).where(Campaign.id == campaign_id) + ) + campaign = campaign_result.scalar_one_or_none() + campaign_workfront_id = campaign.workfront_id if campaign else None + + # Use campaign's workfront_id as base, or proof's existing workfront_id, + # or generate random one as fallback import random - base_id = proof.workfront_id or f"#WF_{random.randint(10000, 99999)}" + base_id = proof.workfront_id or campaign_workfront_id or f"#WF_{random.randint(10000, 99999)}" version_workfront_id = f"{base_id.split('-V')[0]}-V{new_version_number}" if not proof.workfront_id: diff --git a/frontend/components/CreateCampaignModal.tsx b/frontend/components/CreateCampaignModal.tsx index bcfb24b..0346fd3 100755 --- a/frontend/components/CreateCampaignModal.tsx +++ b/frontend/components/CreateCampaignModal.tsx @@ -37,13 +37,18 @@ export const CreateCampaignModal: React.FC = ({ isOpen }, [isOpen]); const validateWorkfrontId = (id: string): boolean => { + // Empty is valid (field is optional) + if (id.length === 0) { + setError(null); + return true; + } const isValid = /^#WF_\d+$/.test(id); - if (!isValid && id.length > 0) { + if (!isValid) { setError("Workfront Campaign ID must be in the format '#WF_12345'"); } else { setError(null); } - return isValid || id.length === 0; + return isValid; }; const handleWorkfrontIdChange = (e: React.ChangeEvent) => { @@ -54,25 +59,25 @@ export const CreateCampaignModal: React.FC = ({ isOpen const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - const isIdValidOnSubmit = /^#WF_\d+$/.test(workfrontId); - if (!name.trim() || !clientLead.trim() || !agencyLead.trim() || !workfrontId.trim() || !selectedBrandGuideline.trim()) { + if (!name.trim() || !clientLead.trim() || !agencyLead.trim() || !selectedBrandGuideline.trim()) { return; } - if (!isIdValidOnSubmit) { + // Validate workfrontId format only if provided + if (workfrontId.trim() && !/^#WF_\d+$/.test(workfrontId)) { setError("Workfront Campaign ID must be in the format '#WF_12345'"); return; } setError(null); - onAddCampaign({ name, workfrontId, clientLead, agencyLead, brandGuidelines: selectedBrandGuideline }); + onAddCampaign({ name, workfrontId: workfrontId.trim(), clientLead, agencyLead, brandGuidelines: selectedBrandGuideline }); onClose(); }; if (!isOpen) return null; - const isFormInvalid = !name.trim() || !workfrontId.trim() || !clientLead.trim() || !agencyLead.trim() || !selectedBrandGuideline.trim(); + const isFormInvalid = !name.trim() || !clientLead.trim() || !agencyLead.trim() || !selectedBrandGuideline.trim(); return (
= ({ isOpen
- + = ({ isOpen onChange={handleWorkfrontIdChange} className={`mt-1 block w-full p-2 border rounded-md shadow-sm focus:ring-brand-accent focus:border-brand-accent transition bg-white text-gray-900 placeholder:text-gray-400 ${error ? 'border-red-500 focus:border-red-500 focus:ring-red-500' : 'border-gray-300'}`} placeholder="#WF_12345" - required aria-invalid={!!error} aria-describedby="workfront-id-error" />