this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

adding tags

daviddao 1e1044fd a67b52ff

+114 -15
+114 -15
app/project/[id]/page.tsx
··· 93 93 }, [projectStatus, profile]) 94 94 95 95 const handleEdit = (field: string) => { 96 + if (field === 'categories') { 97 + // Initialize categoriesInput with current categories as comma-separated string 98 + setEditValues({ 99 + ...editValues, 100 + categoriesInput: projectStatus?.categories?.join(', ') || '' 101 + }) 102 + } 96 103 setEditingField(field) 97 104 } 98 105 ··· 114 121 annualBudget: projectStatus?.annualBudget || 0, 115 122 teamSize: projectStatus?.teamSize || 0, 116 123 sustainableRevenuePercent: projectStatus?.sustainableRevenuePercent || 0, 117 - categories: projectStatus?.categories || [], 124 + categories: field === 'categories' ? 125 + (editValues.categoriesInput ? 126 + editValues.categoriesInput.split(',').map((c: string) => c.trim()).filter((c: string) => c.length > 0) : 127 + editValues[field] || []) : 128 + (projectStatus?.categories || []), 118 129 impactMetrics: projectStatus?.impactMetrics || [], 119 130 geographicDistribution: projectStatus?.geographicDistribution || [], 120 131 } ··· 130 141 if (response.ok) { 131 142 // Update local state 132 143 setProjectStatus({...projectStatus, ...updatedData}) 144 + // Clear temporary input values 145 + setEditValues({ 146 + ...editValues, 147 + categoriesInput: undefined 148 + }) 133 149 setEditingField(null) 134 150 console.log('Successfully saved', field) 135 151 } else { ··· 146 162 } 147 163 148 164 const handleCancel = () => { 165 + // Clear any temporary input values 166 + setEditValues({ 167 + ...editValues, 168 + categoriesInput: undefined 169 + }) 149 170 setEditingField(null) 150 171 } 151 172 ··· 435 456 </div> 436 457 </div> 437 458 438 - {/* Categories */} 439 - <div className="flex flex-wrap gap-1 mb-4 sm:mb-6"> 440 - {project?.categories?.length ? ( 441 - project.categories.map((category: string) => ( 442 - <span 443 - key={category} 444 - className="inline-flex items-center px-2 py-1 text-xs font-medium bg-accent-light text-secondary" 445 - > 446 - {category} 447 - </span> 448 - )) 459 + {/* Categories - Editable */} 460 + <div className="flex flex-wrap gap-1 mb-4 sm:mb-6 group"> 461 + {editingField === 'categories' ? ( 462 + <div className="w-full"> 463 + {/* Preview tags in real-time */} 464 + <div className="flex flex-wrap gap-1 mb-2"> 465 + {(() => { 466 + const inputValue = editValues.categoriesInput || editValues.categories?.join(', ') || ''; 467 + const tags = inputValue 468 + .split(',') 469 + .map((tag: string) => tag.trim()) 470 + .filter((tag: string) => tag.length > 0); 471 + 472 + return tags.map((tag: string, index: number) => ( 473 + <span 474 + key={`${tag}-${index}`} 475 + className="inline-flex items-center px-2 py-1 text-xs font-medium bg-accent-light text-secondary border border-accent/20 rounded animate-in fade-in duration-150" 476 + > 477 + {tag} 478 + </span> 479 + )); 480 + })()} 481 + {/* Show partial tag being typed */} 482 + {(() => { 483 + const inputValue = editValues.categoriesInput || ''; 484 + const lastCommaIndex = inputValue.lastIndexOf(','); 485 + const partialTag = inputValue.slice(lastCommaIndex + 1).trim(); 486 + 487 + if (partialTag && !inputValue.endsWith(',')) { 488 + return ( 489 + <span className="inline-flex items-center px-2 py-1 text-xs font-medium bg-surface-hover text-muted border border-dashed border-border rounded"> 490 + {partialTag} 491 + </span> 492 + ); 493 + } 494 + return null; 495 + })()} 496 + </div> 497 + 498 + {/* Input field */} 499 + <div className="flex items-center gap-2"> 500 + <input 501 + type="text" 502 + value={editValues.categoriesInput || editValues.categories?.join(', ') || ''} 503 + onChange={(e) => { 504 + setEditValues({...editValues, categoriesInput: e.target.value}); 505 + }} 506 + onKeyDown={(e) => handleKeyDown(e, 'categories')} 507 + className="text-xs bg-transparent border border-accent rounded px-2 py-1 focus:outline-none flex-1" 508 + placeholder="Type tags and separate with commas..." 509 + autoFocus 510 + /> 511 + <button 512 + onClick={() => handleSave('categories')} 513 + disabled={saving} 514 + className="p-1 text-accent hover:text-accent-hover disabled:opacity-50" 515 + > 516 + <Save className="h-3 w-3" /> 517 + </button> 518 + <button 519 + onClick={handleCancel} 520 + className="p-1 text-muted hover:text-primary" 521 + > 522 + <X className="h-3 w-3" /> 523 + </button> 524 + </div> 525 + </div> 449 526 ) : ( 450 - <span className="inline-flex items-center px-2 py-1 text-xs font-medium bg-surface-hover text-muted border-dashed border border-border"> 451 - + Add categories 452 - </span> 527 + <div className="flex flex-wrap gap-1"> 528 + {project?.categories?.length ? ( 529 + project.categories.map((category: string) => ( 530 + <span 531 + key={category} 532 + className="inline-flex items-center px-2 py-1 text-xs font-medium bg-accent-light text-secondary" 533 + > 534 + {category} 535 + </span> 536 + )) 537 + ) : ( 538 + <span className="inline-flex items-center px-2 py-1 text-xs font-medium bg-surface-hover text-muted border-dashed border border-border"> 539 + {isOwnProject ? '+ Add categories' : 'No categories set'} 540 + </span> 541 + )} 542 + {isOwnProject && ( 543 + <button 544 + onClick={() => handleEdit('categories')} 545 + className="inline-flex items-center px-2 py-1 text-xs font-medium bg-surface-hover text-muted hover:text-primary border-dashed border border-border opacity-0 group-hover:opacity-100 transition-opacity ml-1" 546 + > 547 + <Edit2 className="h-3 w-3 mr-1" /> 548 + Edit 549 + </button> 550 + )} 551 + </div> 453 552 )} 454 553 </div> 455 554