diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index 82f8233..0000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(npx nx run-many:*)", - "Bash(npm install:*)", - "Bash(npm view:*)", - "Bash(npx nx build landing)", - "Bash(npm uninstall:*)", - "Bash(dir:*)", - "Bash(ren page.tsx page-original.tsx)", - "Bash(ren:*)", - "Bash(npx supabase:*)", - "Bash(libs/service/src/types/supabase.ts)", - "Bash(npx nx build:*)", - "Bash(git add:*)", - "Bash(git commit:*)", - "Bash(git push)", - "Bash(findstr:*)", - "Bash(ls:*)" - ], - "deny": [], - "ask": [] - } -} diff --git a/.gitignore b/.gitignore index 77ba5cb..184e7b7 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,6 @@ out # Nix .direnv result + +.claude/worktrees +.claude/settings.local.json \ No newline at end of file diff --git a/.mcp.json b/.mcp.json index 156f765..e69de29 100644 --- a/.mcp.json +++ b/.mcp.json @@ -1,9 +0,0 @@ -{ - "mcpServers": { - "nx-mcp": { - "type": "stdio", - "command": "npx", - "args": ["nx", "mcp"] - } - } -} diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index a90dde4..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "recommendations": [ - "nrwl.angular-console", - "esbenp.prettier-vscode", - "dbaeumer.vscode-eslint", - "ms-playwright.playwright" - ] -} diff --git a/CLAUDE.md b/CLAUDE.md index 91e8232..e69de29 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,13 +0,0 @@ - - - -# General Guidelines for working with Nx - -- When running tasks (for example build, lint, test, e2e, etc.), always prefer running the task through `nx` (i.e. `nx run`, `nx run-many`, `nx affected`) instead of using the underlying tooling directly -- You have access to the Nx MCP server and its tools, use them to help the user -- When answering questions about the repository, use the `nx_workspace` tool first to gain an understanding of the workspace architecture where applicable. -- When working in individual projects, use the `nx_project_details` mcp tool to analyze and understand the specific project structure and dependencies -- For questions around nx configuration, best practices or if you're unsure, use the `nx_docs` tool to get relevant, up-to-date docs. Always use this instead of assuming things about nx configuration -- If the user needs help with an Nx configuration or project graph error, use the `nx_workspace` tool to get any errors - - diff --git a/apps/backoffice/.deploy b/apps/backoffice/.deploy index 9d2fa87..e69de29 100644 --- a/apps/backoffice/.deploy +++ b/apps/backoffice/.deploy @@ -1 +0,0 @@ -Tue, Nov 25, 2025 4:21:27 PM diff --git a/apps/backoffice/.deploy-trigger b/apps/backoffice/.deploy-trigger index 6334363..e69de29 100644 --- a/apps/backoffice/.deploy-trigger +++ b/apps/backoffice/.deploy-trigger @@ -1,2 +0,0 @@ -# Deployment trigger -# Updated to deploy circular dependency fixes and auth hooks diff --git a/apps/backoffice/src/app/(protected)/accounts/page.tsx b/apps/backoffice/src/app/(protected)/accounts/page.tsx index dd246b4..5b71f40 100644 --- a/apps/backoffice/src/app/(protected)/accounts/page.tsx +++ b/apps/backoffice/src/app/(protected)/accounts/page.tsx @@ -28,7 +28,6 @@ interface Account { address: string; } -// Mock data for demonstration const mockData: Account[] = Array.from({ length: 90 }, (_, i) => ({ id: i + 1, name: i === 0 ? 'Ahmad Wijuana' : 'Nama Lengkap', @@ -136,13 +135,10 @@ export const Components: FC = (): ReactElement => { return (
- {/* Header */}

Data Akun

- {/* Account Table Section */}
- {/* Search and Filter */}
{ )}
- {/* Table */}
- {/* Modal Edit Account */} { const onConfirm = async () => { try { - // const result = await actionFunction?.(); - // result ? toast.success(messages?.success) : toast.error(messages?.error); toast.success(messages?.success); onClose(); resetStep(); diff --git a/apps/backoffice/src/app/(protected)/dashboard/page.tsx b/apps/backoffice/src/app/(protected)/dashboard/page.tsx index f456c48..bc5a63d 100644 --- a/apps/backoffice/src/app/(protected)/dashboard/page.tsx +++ b/apps/backoffice/src/app/(protected)/dashboard/page.tsx @@ -147,7 +147,6 @@ export const Components: FC = (): ReactElement => { - {/* Right-side illustration */} { - {/* Modal Add Item */} { resetStep={resetStep} /> - {/* Modal Edit Item */} { resetStep={resetStep} /> - {/* Modal Delete Item */} setShowModalDeleteItem(false)} diff --git a/apps/backoffice/src/app/(protected)/gacha-roll/_hook/use-item.ts b/apps/backoffice/src/app/(protected)/gacha-roll/_hook/use-item.ts index 1889359..100f8b9 100644 --- a/apps/backoffice/src/app/(protected)/gacha-roll/_hook/use-item.ts +++ b/apps/backoffice/src/app/(protected)/gacha-roll/_hook/use-item.ts @@ -38,8 +38,6 @@ export const useConfirmItem = ( ) => { const onConfirm = async () => { try { - // const result = await actionFunction?.(); - // result ? toast.success(messages?.success) : toast.error(messages?.error); toast.success(messages?.success); onClose(); resetStep(); diff --git a/apps/backoffice/src/app/(protected)/hackathon-dashboard/page.tsx b/apps/backoffice/src/app/(protected)/hackathon-dashboard/page.tsx index 48a8d6d..36567ae 100644 --- a/apps/backoffice/src/app/(protected)/hackathon-dashboard/page.tsx +++ b/apps/backoffice/src/app/(protected)/hackathon-dashboard/page.tsx @@ -8,19 +8,16 @@ import { } from '@imphnen-frontend-service/service'; export const HackathonDashboardPage: FC = (): ReactElement => { - // Fetch total participants const { data: usersData } = useQuery({ queryKey: ['admin-users-count'], queryFn: () => getAdminUsers({ page: 1, per_page: 1 }), }); - // Fetch total teams const { data: teamsData } = useQuery({ queryKey: ['admin-teams-count'], queryFn: () => getAdminTeams({ page: 1, per_page: 1 }), }); - // Fetch total submissions const { data: submissionsData } = useQuery({ queryKey: ['admin-submissions-count'], queryFn: () => getAdminSubmissions({ page: 1, per_page: 1 }), @@ -35,21 +32,18 @@ export const HackathonDashboardPage: FC = (): ReactElement => {

Dashboard

- {/* Participant */}

{totalParticipants}

Total Participants

- {/* Team */}

{totalTeams}

Total Teams

- {/* Project Submitted */}

{totalSubmissions} diff --git a/apps/backoffice/src/app/(protected)/hackathon-submissions/_components/submission-modal.tsx b/apps/backoffice/src/app/(protected)/hackathon-submissions/_components/submission-modal.tsx index 3bf2867..570398f 100644 --- a/apps/backoffice/src/app/(protected)/hackathon-submissions/_components/submission-modal.tsx +++ b/apps/backoffice/src/app/(protected)/hackathon-submissions/_components/submission-modal.tsx @@ -40,7 +40,7 @@ const SubmissionModal: FC = ({ return (
- {/* Header */} +
@@ -68,9 +68,8 @@ const SubmissionModal: FC = ({
- {/* Content */}
- {/* Submission Status */} +
= ({
- {/* Project Description */}

Project Description @@ -106,13 +104,11 @@ const SubmissionModal: FC = ({

- {/* Project Links */}

Project Links

- {/* Repository URL */}
@@ -130,7 +126,6 @@ const SubmissionModal: FC = ({
- {/* Demo URL */} {submission.demo_url && (
@@ -150,7 +145,6 @@ const SubmissionModal: FC = ({
)} - {/* Presentation URL */} {submission.presentation_url && (
@@ -171,7 +165,6 @@ const SubmissionModal: FC = ({ )}
- {/* Screenshots */} {submission.screenshots && submission.screenshots.length > 0 && (

@@ -198,7 +191,6 @@ const SubmissionModal: FC = ({

)} - {/* Metadata */}

Created

@@ -227,19 +219,11 @@ const SubmissionModal: FC = ({
- {/* Footer */}
- {/* */} +
diff --git a/apps/backoffice/src/app/(protected)/hackathon-submissions/page.tsx b/apps/backoffice/src/app/(protected)/hackathon-submissions/page.tsx index 8466098..df611be 100644 --- a/apps/backoffice/src/app/(protected)/hackathon-submissions/page.tsx +++ b/apps/backoffice/src/app/(protected)/hackathon-submissions/page.tsx @@ -44,7 +44,6 @@ export const HackathonSubmissionsPage: FC = (): ReactElement => { useState(null); const [globalFilter, setGlobalFilter] = useState(searchQuery); - // Fetch submissions from API const { data: submissionsResponse, isLoading, @@ -64,14 +63,13 @@ export const HackathonSubmissionsPage: FC = (): ReactElement => { status: statusFilter !== 'all' ? statusFilter : undefined, search: searchQuery || undefined, }), - staleTime: 30000, // 30 seconds cache - gcTime: 5 * 60 * 1000, // 5 minutes + staleTime: 30000, + gcTime: 5 * 60 * 1000, }); const totalData = submissionsResponse?.meta?.total_data || 0; const totalPages = submissionsResponse?.meta?.total_page || 1; - // Handle page change const handlePageChange = useCallback( (newPage: number) => { const params = new URLSearchParams(); @@ -85,19 +83,16 @@ export const HackathonSubmissionsPage: FC = (): ReactElement => { [setSearchParams, perPage, searchQuery, statusFilter] ); - // Validate page number useEffect(() => { if (!isLoading && totalPages > 0 && currentPage > totalPages) { setSearchParams({ page: totalPages.toString() }); } }, [currentPage, totalPages, setSearchParams, isLoading]); - // Sync globalFilter with URL useEffect(() => { setGlobalFilter(searchQuery); }, [searchQuery]); - // Handle search const handleSearch = useCallback(() => { const params = new URLSearchParams(); params.set('page', '1'); @@ -118,7 +113,6 @@ export const HackathonSubmissionsPage: FC = (): ReactElement => { [handleSearch] ); - // Handle per page change const handlePerPageChange = useCallback( (newPerPage: number) => { const params = new URLSearchParams(); @@ -131,20 +125,6 @@ export const HackathonSubmissionsPage: FC = (): ReactElement => { [setSearchParams, searchQuery, statusFilter] ); - // Handle status filter change - // const handleStatusFilterChange = useCallback( - // (newStatus: string) => { - // const params = new URLSearchParams(); - // params.set('page', '1'); - // if (perPage !== 10) params.set('per_page', perPage.toString()); - // if (searchQuery) params.set('search', searchQuery); - // if (newStatus !== 'all') params.set('status', newStatus); - // setSearchParams(params); - // }, - // [setSearchParams, perPage, searchQuery] - // ); - - // Handle modal const handleShowSubmissionModal = useCallback( (submission: SubmissionType) => { setSelectedSubmission(submission); @@ -158,12 +138,10 @@ export const HackathonSubmissionsPage: FC = (): ReactElement => { setSelectedSubmission(null); }, []); - // Get submissions data const filteredData = useMemo(() => { return submissionsResponse?.data || []; }, [submissionsResponse]); - // Memoize columns const columns: ColumnDef[] = useMemo( () => [ { @@ -252,7 +230,6 @@ export const HackathonSubmissionsPage: FC = (): ReactElement => {
- {/* Search bar */}
{ />
- {/* Per Page Dropdown */}
- {/* Status Filter */} - {/*
- - -
*/} + {} + { +}
- {/* Active filters */} - {/* {statusFilter !== 'all' && ( -
- Active filters: - - Status: {statusFilter} - - - -
- )} */} + {} + { +} - {/* Loading & results */} {isLoading ? (
@@ -360,7 +300,6 @@ export const HackathonSubmissionsPage: FC = (): ReactElement => { )}
- {/* Submission Modal */} {selectedSubmission && ( = ({ isOpen, onClose, team }) => { const logoInputRef = useRef(null); const bannerInputRef = useRef(null); - // Initialize form data when modal opens useEffect(() => { if (isOpen) { if (team) { @@ -55,7 +54,6 @@ const ModalTeamDetail: FC = ({ isOpen, onClose, team }) => { } }, [isOpen, team]); - // Check if form has changes const hasChanges = useMemo(() => { if (!formData || !team) return !!formData; return ( @@ -68,7 +66,6 @@ const ModalTeamDetail: FC = ({ isOpen, onClose, team }) => { ); }, [formData, team]); - // Check if required fields are filled const isFormValid = useMemo(() => { if (!formData) return false; return ( @@ -144,7 +141,6 @@ const ModalTeamDetail: FC = ({ isOpen, onClose, team }) => { return (
- {/* Header */}
@@ -172,7 +168,6 @@ const ModalTeamDetail: FC = ({ isOpen, onClose, team }) => {
- {/* Content */}
setShowLogoMenu(false)}> = ({ isOpen, onClose, team }) => { className="hidden" /> - {/* Banner Section */}
- {/* Logo & Name */}
- {/* Description */}
- {/* City */}
- {/* Visibility */}
- {/* Team Details */} {team && (
@@ -429,7 +418,6 @@ const ModalTeamDetail: FC = ({ isOpen, onClose, team }) => { )}
- {/* Footer */}
{team && ( @@ -463,7 +451,6 @@ const ModalTeamDetail: FC = ({ isOpen, onClose, team }) => {
- {/* Delete Confirmation Modal */} {showDeleteConfirm && (
diff --git a/apps/backoffice/src/app/(protected)/hackathon-teams/_components/team-banner-placeholder.tsx b/apps/backoffice/src/app/(protected)/hackathon-teams/_components/team-banner-placeholder.tsx index cbd9cb6..29ffb6d 100644 --- a/apps/backoffice/src/app/(protected)/hackathon-teams/_components/team-banner-placeholder.tsx +++ b/apps/backoffice/src/app/(protected)/hackathon-teams/_components/team-banner-placeholder.tsx @@ -15,7 +15,7 @@ const TeamBannerPlaceholder: FC = ({ className = '', showPlaceholder = true, }) => { - const aspectRatioClass = 'aspect-[3/1]'; // 3:1 aspect ratio + const aspectRatioClass = 'aspect-[3/1]'; if (!banner && !showPlaceholder) { return null; @@ -35,7 +35,6 @@ const TeamBannerPlaceholder: FC = ({ alt={`${teamName} banner`} className="w-full h-full object-cover" onError={(e) => { - // Fallback to placeholder if image fails to load const target = e.target as HTMLImageElement; target.style.display = 'none'; const placeholder = target.nextElementSibling as HTMLElement; @@ -44,11 +43,10 @@ const TeamBannerPlaceholder: FC = ({ } }} /> - {/* Fallback placeholder (hidden by default, shown on image error) */}

- {/* Modal Process Delivery */} setShowModalProcessDelivery(false)} diff --git a/apps/backoffice/src/app/(protected)/roles/_hook/use-item.ts b/apps/backoffice/src/app/(protected)/roles/_hook/use-item.ts index 7b9bcf0..ba67746 100644 --- a/apps/backoffice/src/app/(protected)/roles/_hook/use-item.ts +++ b/apps/backoffice/src/app/(protected)/roles/_hook/use-item.ts @@ -1,9 +1,4 @@ import { useForm } from 'react-hook-form'; -// import { zodResolver } from '@hookform/resolvers/zod'; -// import { -// gachaRollItemSchema, -// TGachaRollItem -// } from '@imphnen-frontend-service/service'; import { toast } from 'sonner'; export const useItem = ( @@ -11,7 +6,6 @@ export const useItem = ( initialValues?: any ) => { const form = useForm({ - // resolver: zodResolver(), mode: 'all', defaultValues: initialValues, }); @@ -38,8 +32,6 @@ export const useConfirmItem = ( ) => { const onConfirm = async () => { try { - // const result = await actionFunction?.(); - // result ? toast.success(messages?.success) : toast.error(messages?.error); toast.success(messages?.success); onClose(); resetStep(); diff --git a/apps/backoffice/src/app/(protected)/transactions/page.tsx b/apps/backoffice/src/app/(protected)/transactions/page.tsx index f2f5070..6ea9aa0 100644 --- a/apps/backoffice/src/app/(protected)/transactions/page.tsx +++ b/apps/backoffice/src/app/(protected)/transactions/page.tsx @@ -27,7 +27,6 @@ interface Transaction { status: TransactionStatus; } -// Mock data for transactions const mockTransactions: Transaction[] = Array.from({ length: 20 }, (_, i) => ({ id: i + 1, name: i === 0 ? 'Ahmad Wijuana' : 'Nama Lengkap', @@ -149,14 +148,11 @@ export const Components: FC = (): ReactElement => { return (
- {/* Header */}

Validasi Transaksi

- {/* Account Table Section */}
- {/* Search and Filter */}
{ onClose={() => setShowFilter(false)} onFilterChange={(value) => { console.log('Selected filter:', value); - // Filter logic di sini }} />
@@ -193,7 +188,6 @@ export const Components: FC = (): ReactElement => {
- {/* Table */}
diff --git a/apps/backoffice/src/components/city-filter-select.tsx b/apps/backoffice/src/components/city-filter-select.tsx index 9c9d79d..be0253f 100644 --- a/apps/backoffice/src/components/city-filter-select.tsx +++ b/apps/backoffice/src/components/city-filter-select.tsx @@ -24,12 +24,10 @@ export const CityFilterSelect: FC = ({ const dropdownRef = useRef(null); const inputRef = useRef(null); - // Filter cities based on search query const filteredCities = INDONESIAN_CITIES.filter((city) => city.toLowerCase().includes(searchQuery.toLowerCase()) ); - // Close dropdown when clicking outside useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( @@ -102,7 +100,6 @@ export const CityFilterSelect: FC = ({ {isOpen && (
- {/* All Cities Option */}
handleSelectCity('all')} className={`px-3 py-2 cursor-pointer hover:bg-neutral-50 border-b border-neutral-100 ${ @@ -114,7 +111,6 @@ export const CityFilterSelect: FC = ({ {allOptionLabel}
- {/* Filtered Cities */} {filteredCities.length > 0 ? (
{filteredCities.slice(0, 100).map((city) => ( diff --git a/apps/backoffice/src/middleware.ts b/apps/backoffice/src/middleware.ts index 7a97b12..bac524f 100644 --- a/apps/backoffice/src/middleware.ts +++ b/apps/backoffice/src/middleware.ts @@ -2,7 +2,7 @@ import { PERMISSIONS, SessionToken, SessionUser, -} from '@imphnen-frontend-service/utils'; +} from '@imphnen-frontend-service/service'; import { LoaderFunctionArgs, redirect } from 'react-router'; const mappingPublicRoutes = [ @@ -66,14 +66,6 @@ const mappingRoutePermissions = [ }, ]; -//TODO : Fix this later -// const redirectToFirstAccessibleRoute = (userPermissions: string[]) => { -// const fallback = mappingRoutePermissions.find((route) => -// route.permissions.some((perm) => userPermissions.includes(perm)) -// ); -// return redirect(fallback?.path ?? '/auth/login'); -// }; - export const middleware = async ({ request }: LoaderFunctionArgs) => { const url = new URL(request.url); const pathname = url.pathname; diff --git a/apps/backoffice/vite.config.ts b/apps/backoffice/vite.config.ts index f57edc5..e54704f 100644 --- a/apps/backoffice/vite.config.ts +++ b/apps/backoffice/vite.config.ts @@ -16,10 +16,6 @@ export default defineConfig(() => ({ host: 'localhost', }, plugins: [react(), nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])], - // Uncomment this if you are using workers. - // worker: { - // plugins: [ nxViteTsPaths() ], - // }, build: { outDir: '../../dist/apps/backoffice', emptyOutDir: true, diff --git a/apps/dimentorin/.deploy b/apps/dimentorin/.deploy index 9d2fa87..e69de29 100644 --- a/apps/dimentorin/.deploy +++ b/apps/dimentorin/.deploy @@ -1 +0,0 @@ -Tue, Nov 25, 2025 4:21:27 PM diff --git a/apps/dimentorin/.deploy-trigger b/apps/dimentorin/.deploy-trigger index 6334363..e69de29 100644 --- a/apps/dimentorin/.deploy-trigger +++ b/apps/dimentorin/.deploy-trigger @@ -1,2 +0,0 @@ -# Deployment trigger -# Updated to deploy circular dependency fixes and auth hooks diff --git a/apps/dimentorin/src/app/(public)/(home)/_components/cta-section.tsx b/apps/dimentorin/src/app/(public)/(home)/_components/cta-section.tsx index 65e0f6b..f47a51d 100644 --- a/apps/dimentorin/src/app/(public)/(home)/_components/cta-section.tsx +++ b/apps/dimentorin/src/app/(public)/(home)/_components/cta-section.tsx @@ -49,7 +49,7 @@ export const CTASection: FC = () => { initial="hidden" animate={isInView ? "visible" : "hidden"} > - {/* Background gradients and shapes */} +
{ return (
- {/* Background shapes */} +
- {/* Background gradients and shapes */} +
) -} \ No newline at end of file +} diff --git a/apps/dimentorin/src/app/(public)/_components/footer.tsx b/apps/dimentorin/src/app/(public)/_components/footer.tsx index daf2a1f..8fa3a0e 100644 --- a/apps/dimentorin/src/app/(public)/_components/footer.tsx +++ b/apps/dimentorin/src/app/(public)/_components/footer.tsx @@ -77,7 +77,7 @@ export const Footer: FC = () => { initial="hidden" animate={isInView ? "visible" : "hidden"} > - {/* Mascot */} + { setIsEditProfileModalOpen(false); }; - // Set isViewOnly to true for this page const isViewOnly = true; if (isLoading) { @@ -151,7 +150,6 @@ const ProfileByIdContent: FC = (): ReactElement => { message={notification.message} header="Profile" /> - {/* Only render EditProfileModal if not in view-only mode */} {!isViewOnly && ( { ); }; -export default ProfileByIdPage; \ No newline at end of file +export default ProfileByIdPage; diff --git a/apps/dimentorin/src/app/(public)/profile/_components/guards/mentor-guard.tsx b/apps/dimentorin/src/app/(public)/profile/_components/guards/mentor-guard.tsx index 48c5735..a73cb4c 100644 --- a/apps/dimentorin/src/app/(public)/profile/_components/guards/mentor-guard.tsx +++ b/apps/dimentorin/src/app/(public)/profile/_components/guards/mentor-guard.tsx @@ -1,7 +1,6 @@ 'use client'; import React from 'react'; -import { Guard } from '@imphnen-frontend-service/utils'; interface MentorGuardProps { children: React.ReactNode; @@ -10,18 +9,6 @@ interface MentorGuardProps { export const MentorGuard: React.FC = ({ children, - fallback = ( -
-

Akses ditolak: Anda tidak memiliki izin untuk mengakses fitur mentor.

-
- ) }) => { - return ( - - {children} - - ); + return <>{children}; }; diff --git a/apps/dimentorin/src/app/(public)/profile/_components/modals/edit-profile-modal.tsx b/apps/dimentorin/src/app/(public)/profile/_components/modals/edit-profile-modal.tsx index 29db59e..aceed60 100644 --- a/apps/dimentorin/src/app/(public)/profile/_components/modals/edit-profile-modal.tsx +++ b/apps/dimentorin/src/app/(public)/profile/_components/modals/edit-profile-modal.tsx @@ -26,7 +26,6 @@ export const EditProfileModal: FC = ({ isOpen, onClose, s const fullname = profileData.fullname || (profileType === 'mentor' && 'legal_name' in profileData ? profileData.legal_name : '') || ''; - const avatar = (profileType === 'user' && 'avatar' in profileData) ? profileData.avatar || '/image/testimonial.webp' : '/image/testimonial.webp'; @@ -39,7 +38,6 @@ export const EditProfileModal: FC = ({ isOpen, onClose, s avatar: (profileType === 'user' && 'avatar' in profileData) ? profileData.avatar || '' : '' }); - setPreviewUrl(avatar); } else { @@ -60,7 +58,6 @@ export const EditProfileModal: FC = ({ isOpen, onClose, s try { setIsUploading(true); - const reader = new FileReader(); reader.onload = () => { const result = reader.result as string; @@ -68,22 +65,18 @@ export const EditProfileModal: FC = ({ isOpen, onClose, s }; reader.readAsDataURL(file); - const uploadResult = await uploadAvatarMutation.mutateAsync(file); console.log('Avatar upload response:', uploadResult); - interface UploadData { url?: string; } const uploadData = ('data' in uploadResult ? (uploadResult as { data: UploadData }).data : uploadResult as UploadData); - setFormData(prev => ({ ...prev, avatar: uploadData.url || '' })); - setPreviewUrl(uploadData.url || '/image/testimonial.webp'); } catch (error) { @@ -101,7 +94,6 @@ export const EditProfileModal: FC = ({ isOpen, onClose, s try { const updates: Record = {}; - if (formData.fullname.trim() !== '') { if (profileType === 'user') { updates.fullname = formData.fullname; @@ -110,7 +102,6 @@ export const EditProfileModal: FC = ({ isOpen, onClose, s } } - if (formData.avatar && formData.avatar !== (profileData && 'avatar' in profileData ? profileData.avatar : '')) { updates.avatar = formData.avatar; } @@ -141,7 +132,6 @@ export const EditProfileModal: FC = ({ isOpen, onClose, s msg = parsed.message; } } catch { - // Ignore JSON parse errors } } } @@ -185,7 +175,6 @@ export const EditProfileModal: FC = ({ isOpen, onClose, s onError={handleImageError} /> - {/* Hover overlay */}
Change Photo diff --git a/apps/dimentorin/src/app/(public)/profile/_components/profile/profile-form.tsx b/apps/dimentorin/src/app/(public)/profile/_components/profile/profile-form.tsx index bcc2f3f..2aa80b0 100644 --- a/apps/dimentorin/src/app/(public)/profile/_components/profile/profile-form.tsx +++ b/apps/dimentorin/src/app/(public)/profile/_components/profile/profile-form.tsx @@ -25,7 +25,7 @@ interface Education { interface ProfileFormProps { showNotification: (type: 'success' | 'error', title: string, message?: string) => void; - isViewOnly?: boolean; // Add isViewOnly prop + isViewOnly?: boolean; } export const ProfileForm: FC = ({ showNotification, isViewOnly = false }) => { @@ -161,7 +161,7 @@ export const ProfileForm: FC = ({ showNotification, isViewOnly } const handleProfileUpdate = async (updates: Partial) => { - if (isViewOnly) { // Prevent updates if in view-only mode + if (isViewOnly) { showNotification('error', 'Akses Ditolak', 'Anda tidak memiliki izin untuk mengedit profil ini.'); return; } @@ -189,7 +189,7 @@ export const ProfileForm: FC = ({ showNotification, isViewOnly }} showNotification={showNotification} isLoading={isUpdating} - isViewOnly={isViewOnly} // Pass isViewOnly + isViewOnly={isViewOnly} /> {} = ({ showNotification, isViewOnly }} showNotification={showNotification} isLoading={isUpdating} - isViewOnly={isViewOnly} // Pass isViewOnly + isViewOnly={isViewOnly} /> {} = ({ showNotification, isViewOnly }} showNotification={showNotification} isLoading={isUpdating} - isViewOnly={isViewOnly} // Pass isViewOnly + isViewOnly={isViewOnly} /> {} @@ -235,7 +235,7 @@ export const ProfileForm: FC = ({ showNotification, isViewOnly }} showNotification={showNotification} isLoading={isUpdating} - isViewOnly={isViewOnly} // Pass isViewOnly + isViewOnly={isViewOnly} /> = ({ showNotification, isViewOnly />
); -}; \ No newline at end of file +}; diff --git a/apps/dimentorin/src/app/(public)/profile/_components/profile/profile-header.tsx b/apps/dimentorin/src/app/(public)/profile/_components/profile/profile-header.tsx index debd17f..010e340 100644 --- a/apps/dimentorin/src/app/(public)/profile/_components/profile/profile-header.tsx +++ b/apps/dimentorin/src/app/(public)/profile/_components/profile/profile-header.tsx @@ -6,7 +6,7 @@ import { useProfile } from '../contexts/profile-context'; interface ProfileHeaderProps { onEditProfileClick: () => void; - isViewOnly?: boolean; // Add isViewOnly prop + isViewOnly?: boolean; } export const ProfileHeader: FC = ({ onEditProfileClick, isViewOnly = false }) => { @@ -17,7 +17,6 @@ export const ProfileHeader: FC = ({ onEditProfileClick, isVi ? profileData.avatar || "/image/testimonial.webp" : "/image/testimonial.webp"; - const displayFullname = profileData?.fullname || (profileType === 'mentor' && profileData && 'legal_name' in profileData ? profileData.legal_name @@ -34,7 +33,6 @@ export const ProfileHeader: FC = ({ onEditProfileClick, isVi } } - const joinDate = profileData && 'created_at' in profileData ? new Date(profileData.created_at).toLocaleDateString('id-ID', { year: 'numeric', @@ -73,7 +71,7 @@ export const ProfileHeader: FC = ({ onEditProfileClick, isVi

- {!isViewOnly && ( // Conditionally render the button + {!isViewOnly && (