diff --git a/apps/backoffice/src/app/(protected)/hackathon-teams/_components/modal-team-detail-new.tsx b/apps/backoffice/src/app/(protected)/hackathon-teams/_components/modal-team-detail-new.tsx index 23423aa..68d119a 100644 --- a/apps/backoffice/src/app/(protected)/hackathon-teams/_components/modal-team-detail-new.tsx +++ b/apps/backoffice/src/app/(protected)/hackathon-teams/_components/modal-team-detail-new.tsx @@ -1,7 +1,8 @@ -import { FC, useState, useEffect, useMemo } from 'react'; +import { FC, useState, useEffect, useMemo, useRef } from 'react'; import { Button } from '@imphnen-frontend-service/ui/atoms'; import { cn } from '@imphnen-frontend-service/utils'; import TeamBannerPlaceholder from './team-banner-placeholder'; +import { CityFilterSelect } from '../../../../components/city-filter-select'; import { TeamOutlined, CalendarOutlined, @@ -16,6 +17,8 @@ import { CheckCircleOutlined, ClockCircleOutlined, CloseCircleOutlined, + CameraOutlined, + UploadOutlined, } from '@ant-design/icons'; interface TeamMember { @@ -66,6 +69,9 @@ const ModalTeamDetail: FC = ({ isOpen, onClose, team }) => { const [formData, setFormData] = useState(null); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [activeTab, setActiveTab] = useState<'details' | 'members'>('details'); + const [showLogoMenu, setShowLogoMenu] = useState(false); + const logoInputRef = useRef(null); + const bannerInputRef = useRef(null); // Initialize form data when modal opens useEffect(() => { @@ -102,7 +108,9 @@ const ModalTeamDetail: FC = ({ isOpen, onClose, team }) => { formData.name !== team.name || formData.description !== team.description || formData.city !== team.city || - formData.visibility !== team.visibility + formData.visibility !== team.visibility || + formData.logo !== team.logo || + formData.banner !== team.banner ); }, [formData, team]); @@ -125,7 +133,7 @@ const ModalTeamDetail: FC = ({ isOpen, onClose, team }) => { const handleInputChange = ( field: keyof TeamType, - value: string | boolean | 'public' | 'private' + value: string | boolean | 'public' | 'private' | undefined ) => { setFormData((prev) => (prev ? { ...prev, [field]: value } : null)); }; @@ -145,7 +153,59 @@ const ModalTeamDetail: FC = ({ isOpen, onClose, team }) => { onClose(); }; - const cities = ['Jakarta', 'Bandung', 'Surabaya', 'Medan', 'Yogyakarta']; + const handleLogoUpload = (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + if (file) { + if (!file.type.startsWith('image/')) { + alert('Please select an image file'); + return; + } + if (file.size > 5 * 1024 * 1024) { + alert('Image size must be less than 5MB'); + return; + } + const reader = new FileReader(); + reader.onload = (e) => { + const logoUrl = e.target?.result as string; + handleInputChange('logo', logoUrl); + setShowLogoMenu(false); + }; + reader.readAsDataURL(file); + } + }; + + const handleBannerUpload = (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + if (file) { + if (!file.type.startsWith('image/')) { + alert('Please select an image file'); + return; + } + if (file.size > 5 * 1024 * 1024) { + alert('Image size must be less than 5MB'); + return; + } + const reader = new FileReader(); + reader.onload = (e) => { + const bannerUrl = e.target?.result as string; + handleInputChange('banner', bannerUrl); + }; + reader.readAsDataURL(file); + } + }; + + const handleRemoveLogo = () => { + handleInputChange('logo', undefined); + setShowLogoMenu(false); + }; + + const handleRemoveBanner = () => { + handleInputChange('banner', undefined); + }; + + const triggerLogoUpload = () => { + logoInputRef.current?.click(); + }; return (
@@ -169,40 +229,155 @@ const ModalTeamDetail: FC = ({ isOpen, onClose, team }) => {
{/* Content */} -
- {/* Banner Section (for existing teams) */} - {team && ( -
- - -
- )} +
setShowLogoMenu(false)}> + {/* Hidden File Inputs */} + + - {/* Team Name */} + {/* Interactive Banner Section */}
- handleInputChange('name', e.target.value)} - /> +
+ + {/* Banner Action Buttons */} +
+ + {formData.banner && ( + + )} +
+
+
+ + {/* Team Logo & Name Row */} +
+ {/* Interactive Team Logo */} +
+ +
+
+ {formData.logo ? ( + {formData.name + ) : ( + + )} +
+ {/* Logo Hover Overlay - Full circle */} + + + {/* Logo Menu Dropdown */} + {showLogoMenu && ( +
+ + {formData.logo && ( + + )} +
+ )} +
+
+ + {/* Team Name */} +
+ + handleInputChange('name', e.target.value)} + /> +

+ Click logo to upload or change team logo (circular format) +

+
{/* Team Description */} @@ -224,18 +399,16 @@ const ModalTeamDetail: FC = ({ isOpen, onClose, team }) => { - + + handleInputChange('city', city === 'all' ? '' : city) + } + className="w-full" + placeholder="Search cities..." + allOptionLabel="Select a city" + filterIcon={false} + />
{/* Visibility */} @@ -323,7 +496,7 @@ const ModalTeamDetail: FC = ({ isOpen, onClose, team }) => {