diff --git a/src/app/profile/components/bankInformation.tsx b/src/app/profile/components/bankInformation.tsx
new file mode 100644
index 0000000..af97c81
--- /dev/null
+++ b/src/app/profile/components/bankInformation.tsx
@@ -0,0 +1,90 @@
+import React from 'react'
+
+export default function BankInformation({
+ profileData,
+ editingBank,
+ bankDraft,
+ setEditingBank,
+ setBankDraft,
+ setBankInfo,
+ onEdit,
+}: {
+ profileData: any,
+ editingBank: boolean,
+ bankDraft: { accountHolder: string, iban: string },
+ setEditingBank: (v: boolean) => void,
+ setBankDraft: (v: { accountHolder: string, iban: string }) => void,
+ setBankInfo: (v: { accountHolder: string, iban: string }) => void,
+ onEdit?: () => void
+}) {
+ return (
+
+
+
Bank Information
+ {!editingBank && (
+
+ )}
+
+
+
+ )
+}
diff --git a/src/app/profile/components/basicInformation.tsx b/src/app/profile/components/basicInformation.tsx
new file mode 100644
index 0000000..e406d02
--- /dev/null
+++ b/src/app/profile/components/basicInformation.tsx
@@ -0,0 +1,83 @@
+import React from 'react'
+import { UserCircleIcon, EnvelopeIcon, PhoneIcon, MapPinIcon, PencilIcon, CheckCircleIcon } from '@heroicons/react/24/outline'
+
+export default function BasicInformation({ profileData, HighlightIfMissing, onEdit }: {
+ profileData: any,
+ HighlightIfMissing: React.FC<{ value: any, children: React.ReactNode }>
+ onEdit?: () => void
+}) {
+ return (
+
+
+
Basic Information
+
+
+
+
+
+
+
+
+
+ {profileData.firstName}
+
+
+
+
+
+
+
+
+ {profileData.lastName}
+
+
+
+
+
+
+
+
+
+ {profileData.email}
+
+
+
+
+
+
+
+
+
+ {profileData.phone}
+
+
+
+
+
+
+
+
+ {profileData.address}
+
+
+
+
+
+ )
+}
diff --git a/src/app/profile/components/editModal.tsx b/src/app/profile/components/editModal.tsx
new file mode 100644
index 0000000..05e430a
--- /dev/null
+++ b/src/app/profile/components/editModal.tsx
@@ -0,0 +1,100 @@
+import React, { useEffect, useState } from 'react'
+
+export default function EditModal({
+ open,
+ type,
+ fields,
+ values,
+ onChange,
+ onSave,
+ onCancel,
+ children,
+}: {
+ open: boolean,
+ type: 'basic' | 'bank',
+ fields: { key: string, label: string, type?: string }[],
+ values: Record,
+ onChange: (key: string, value: string) => void,
+ onSave: () => void,
+ onCancel: () => void,
+ children?: React.ReactNode
+}) {
+ // Prevent background scroll when modal is open
+ useEffect(() => {
+ if (open) {
+ document.body.style.overflow = 'hidden';
+ } else {
+ document.body.style.overflow = '';
+ }
+ return () => {
+ document.body.style.overflow = '';
+ };
+ }, [open]);
+
+ // Animation state
+ const [show, setShow] = useState(open);
+
+ useEffect(() => {
+ if (open) {
+ setShow(true);
+ } else {
+ // Delay unmount for animation
+ const timeout = setTimeout(() => setShow(false), 200);
+ return () => clearTimeout(timeout);
+ }
+ }, [open]);
+
+ if (!show) return null;
+ return (
+
+
+
+ Edit {type === 'basic' ? 'Basic Information' : 'Bank Information'}
+
+ {children}
+
+
+
+ );
+}
diff --git a/src/app/profile/components/mediaSection.tsx b/src/app/profile/components/mediaSection.tsx
new file mode 100644
index 0000000..b53d7f2
--- /dev/null
+++ b/src/app/profile/components/mediaSection.tsx
@@ -0,0 +1,39 @@
+import React from 'react'
+
+export default function MediaSection({ documents }: { documents: any[] }) {
+ const hasDocuments = Array.isArray(documents) && documents.length > 0;
+ return (
+
+
Media & Documents
+
+ {hasDocuments ? (
+
+
+
+ | Name |
+ Type |
+ Uploaded |
+ |
+
+
+
+ {documents.map(doc => (
+
+ | {doc.name} |
+ {doc.type} |
+ {doc.uploaded} |
+
+
+
+ |
+
+ ))}
+
+
+ ) : (
+
No media or documents found.
+ )}
+
+
+ )
+}
diff --git a/src/app/profile/components/profileCompletion.tsx b/src/app/profile/components/profileCompletion.tsx
new file mode 100644
index 0000000..3642739
--- /dev/null
+++ b/src/app/profile/components/profileCompletion.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+
+export default function ProfileCompletion({ profileComplete }: { profileComplete: number }) {
+ return (
+
+
+
Profile Completion
+
+ {profileComplete}%
+
+
+
+
+ Complete your profile to unlock all features
+
+
+ );
+}
diff --git a/src/app/profile/hooks/editProfile.ts b/src/app/profile/hooks/editProfile.ts
new file mode 100644
index 0000000..f1649bf
--- /dev/null
+++ b/src/app/profile/hooks/editProfile.ts
@@ -0,0 +1,101 @@
+import useAuthStore from '../../store/authStore'
+
+const BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001';
+
+function logEditProfile(message: string, ...args: any[]) {
+ // Simple logger for editProfile actions
+ console.log(`[editProfile] ${message}`, ...args);
+}
+
+// Helper to get userType from sessionStorage (always parses JSON string)
+function getUserType(): string | undefined {
+ if (typeof window !== 'undefined') {
+ try {
+ const userRaw = sessionStorage.getItem('user');
+ logEditProfile('sessionStorage user raw:', userRaw);
+ if (userRaw) {
+ const userObj = JSON.parse(userRaw);
+ logEditProfile('parsed user object:', userObj);
+ logEditProfile('userType:', userObj.userType);
+ return userObj.userType;
+ }
+ } catch (err) {
+ logEditProfile('Error parsing user from sessionStorage:', err);
+ }
+ } else {
+ logEditProfile('window is undefined, SSR context');
+ }
+ return undefined;
+}
+
+export async function editProfileBasic(fields: Partial<{ firstName: string, lastName: string, email: string, phone: string, address: string }>) {
+ const token = useAuthStore.getState().accessToken;
+ const userType = getUserType();
+ logEditProfile('editProfileBasic called', { fields, token, userType });
+ if (userType !== 'personal') {
+ logEditProfile('User type is not personal or undefined:', userType);
+ return { error: 'Personal user required', status: 400, data: null };
+ }
+ // FIX: Add user_type to the request body as required by backend!
+ const payload = { ...fields, user_type: userType };
+ logEditProfile('Sending PATCH /api/profile/personal/basic', { payload });
+ try {
+ const res = await fetch(`${BASE_URL}/api/profile/personal/basic`, {
+ method: 'PATCH',
+ credentials: 'include',
+ headers: {
+ 'Content-Type': 'application/json',
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
+ },
+ body: JSON.stringify(payload),
+ });
+ logEditProfile('Request sent. Awaiting response...');
+ const data = await res.json();
+ logEditProfile('Response received:', { status: res.status, data });
+ if (!res.ok) {
+ logEditProfile('Request failed:', { status: res.status, error: data?.message });
+ return { error: data?.message || 'Update failed', status: res.status, data };
+ }
+ logEditProfile('Request succeeded:', data);
+ return { success: true, data };
+ } catch (e) {
+ logEditProfile('Network error:', e);
+ return { error: 'Network error', status: 0, data: null };
+ }
+}
+
+export async function editProfileBank(fields: Partial<{ accountHolder: string, iban: string }>) {
+ const token = useAuthStore.getState().accessToken;
+ const userType = getUserType();
+ logEditProfile('editProfileBank called', { fields, token, userType });
+ if (userType !== 'personal') {
+ logEditProfile('User type is not personal or undefined:', userType);
+ return { error: 'Personal user required', status: 400, data: null };
+ }
+ // FIX: Add user_type to the request body as required by backend!
+ const payload = { ...fields, iban: fields.iban?.replace(/\s+/g, '').toUpperCase(), user_type: userType };
+ logEditProfile('Sending PATCH /api/profile/personal/bank', { payload });
+ try {
+ const res = await fetch(`${BASE_URL}/api/profile/personal/bank`, {
+ method: 'PATCH',
+ credentials: 'include',
+ headers: {
+ 'Content-Type': 'application/json',
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
+ },
+ body: JSON.stringify(payload),
+ });
+ logEditProfile('Request sent. Awaiting response...');
+ const data = await res.json();
+ logEditProfile('Response received:', { status: res.status, data });
+ if (!res.ok) {
+ logEditProfile('Request failed:', { status: res.status, error: data?.message });
+ return { error: data?.message || 'Update failed', status: res.status, data };
+ }
+ logEditProfile('Request succeeded:', data);
+ return { success: true, data };
+ } catch (e) {
+ logEditProfile('Network error:', e);
+ return { error: 'Network error', status: 0, data: null };
+ }
+}
diff --git a/src/app/profile/hooks/getMedia.ts b/src/app/profile/hooks/getMedia.ts
new file mode 100644
index 0000000..a96e282
--- /dev/null
+++ b/src/app/profile/hooks/getMedia.ts
@@ -0,0 +1,32 @@
+import { useEffect, useState } from 'react'
+import useAuthStore from '../../store/authStore'
+
+const BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001';
+
+export function useMedia(userId: string | number | undefined, refreshKey: number = 0) {
+ const [data, setData] = useState(null)
+ const [loading, setLoading] = useState(false)
+ const [error, setError] = useState(null)
+ const token = useAuthStore.getState().accessToken
+
+ useEffect(() => {
+ if (!userId) return
+ setLoading(true)
+ fetch(`${BASE_URL}/api/users/${userId}/documents`, {
+ credentials: 'include',
+ headers: token ? { Authorization: `Bearer ${token}` } : {},
+ })
+ .then(res => {
+ if (!res.ok) throw new Error('Failed to fetch user documents')
+ return res.json()
+ })
+ .then(data => {
+ console.log('[useMedia] Response:', data)
+ setData(data)
+ })
+ .catch(setError)
+ .finally(() => setLoading(false))
+ }, [userId, token, refreshKey])
+
+ return { data, loading, error }
+}
diff --git a/src/app/profile/hooks/getProfileCompletion.ts b/src/app/profile/hooks/getProfileCompletion.ts
new file mode 100644
index 0000000..62ad615
--- /dev/null
+++ b/src/app/profile/hooks/getProfileCompletion.ts
@@ -0,0 +1,30 @@
+import useAuthStore from "../../store/authStore";
+
+const BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001';
+
+// Fetches the user's profile completion progress from the API, with auth token.
+// Returns either percent or a progress object.
+export async function getProfileCompletion(): Promise {
+ const token = useAuthStore.getState().accessToken;
+ try {
+ const res = await fetch(`${BASE_URL}/api/user/status-progress`, {
+ credentials: 'include',
+ headers: token ? { Authorization: `Bearer ${token}` } : {},
+ });
+ const data = await res.json();
+ console.log('[getProfileCompletion] /api/user/status-progress response:', data);
+ if (data?.progress?.progressPercent !== undefined) {
+ return {
+ progressPercent: data.progress.progressPercent,
+ completedSteps: data.progress.completedSteps ?? [],
+ steps: data.progress.steps ?? [],
+ };
+ }
+ if (typeof data.progress === 'number') return data.progress;
+ if (typeof data.completion === 'number') return data.completion;
+ return null;
+ } catch (e) {
+ console.warn('[getProfileCompletion] Failed to fetch:', e);
+ return null;
+ }
+}
diff --git a/src/app/profile/hooks/getProfileData.ts b/src/app/profile/hooks/getProfileData.ts
new file mode 100644
index 0000000..3e91490
--- /dev/null
+++ b/src/app/profile/hooks/getProfileData.ts
@@ -0,0 +1,43 @@
+import { useEffect, useState } from 'react'
+import useAuthStore from '../../store/authStore'
+
+const BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001';
+
+export function useProfileData(userId: string | number | undefined, refreshKey: number = 0) {
+ const [data, setData] = useState(null)
+ const [loading, setLoading] = useState(false)
+ const [error, setError] = useState(null)
+ const token = useAuthStore.getState().accessToken
+
+ // Log all sessionStorage contents for inspection
+ useEffect(() => {
+ const sessionData: Record = {};
+ for (let i = 0; i < sessionStorage.length; i++) {
+ const key = sessionStorage.key(i);
+ if (key) sessionData[key] = sessionStorage.getItem(key);
+ }
+ console.log('Session Storage Contents:', sessionData);
+ }, []);
+
+ useEffect(() => {
+ if (!userId) return
+ setLoading(true)
+ console.log('[useProfileData] Fetching profile for userId:', userId);
+ fetch(`${BASE_URL}/api/users/${userId}/full`, {
+ credentials: 'include',
+ headers: token ? { Authorization: `Bearer ${token}` } : {},
+ })
+ .then(res => {
+ if (!res.ok) throw new Error('Failed to fetch user data')
+ return res.json()
+ })
+ .then(data => {
+ console.log('[useProfileData] Response:', data); // <-- Log full response
+ setData(data)
+ })
+ .catch(setError)
+ .finally(() => setLoading(false))
+ }, [userId, token, refreshKey])
+
+ return { data, loading, error }
+}
diff --git a/src/app/profile/page.tsx b/src/app/profile/page.tsx
index 1f04f6a..93f4d62 100644
--- a/src/app/profile/page.tsx
+++ b/src/app/profile/page.tsx
@@ -5,6 +5,11 @@ import { useRouter } from 'next/navigation'
import useAuthStore from '../store/authStore'
import Header from '../components/nav/Header'
import Footer from '../components/Footer'
+import ProfileCompletion from './components/profileCompletion'
+import BasicInformation from './components/basicInformation'
+import MediaSection from './components/mediaSection'
+import BankInformation from './components/bankInformation'
+import EditModal from './components/editModal'
import {
UserCircleIcon,
EnvelopeIcon,
@@ -13,11 +18,66 @@ import {
PencilIcon,
CheckCircleIcon
} from '@heroicons/react/24/outline'
+import { getProfileCompletion } from './hooks/getProfileCompletion';
+import { useProfileData } from './hooks/getProfileData';
+import { useMedia } from './hooks/getMedia';
+import { editProfileBasic, editProfileBank } from './hooks/editProfile';
+
+// Helper to display missing fields in subtle gray italic (no yellow highlight)
+function HighlightIfMissing({ value, children }: { value: any, children: React.ReactNode }) {
+ if (value === null || value === undefined || value === '') {
+ return (
+
+ Not provided
+
+ );
+ }
+ return <>{children}>;
+}
+
+// Helper for safe access to profileData fields
+function getProfileField(
+ obj: typeof defaultProfileData,
+ key: T
+) {
+ return obj[key];
+}
+
+// Default profile data for typing
+const defaultProfileData = {
+ firstName: '',
+ lastName: '',
+ email: '',
+ phone: '',
+ address: '',
+ joinDate: '',
+ memberStatus: '',
+ profileComplete: 0,
+ accountHolder: '',
+ iban: '',
+};
export default function ProfilePage() {
const router = useRouter()
const user = useAuthStore(state => state.user)
-
+ const [userId, setUserId] = React.useState(undefined);
+
+ // Update userId when user changes
+ useEffect(() => {
+ if (user?.id) setUserId(user.id);
+ }, [user]);
+
+ // Add refresh key and UI states for smooth refresh
+ const [refreshKey, setRefreshKey] = React.useState(0);
+ const [showRefreshing, setShowRefreshing] = React.useState(false);
+ const [completionLoading, setCompletionLoading] = React.useState(false);
+
+ // Fetch profile data on page load/navigation, now with refreshKey
+ const { data: profileDataApi, loading: profileLoading, error: profileError } = useProfileData(userId, refreshKey);
+
+ // Fetch media/documents for user, now with refreshKey
+ const { data: mediaData, loading: mediaLoading, error: mediaError } = useMedia(userId, refreshKey);
+
// Redirect if not logged in
useEffect(() => {
if (!user) {
@@ -37,39 +97,166 @@ export default function ProfilePage() {
)
}
- // Mock user data for display
- const profileData = {
- firstName: 'Admin',
- lastName: 'User',
- email: user.email || 'office@profit-planet.com',
- phone: '+49 123 456 789',
- address: 'Musterstraße 123, 12345 Berlin',
- joinDate: 'Oktober 2024',
- memberStatus: 'Gold Member',
- profileComplete: 95
- }
+ // Progress bar state
+ const [progressPercent, setProgressPercent] = React.useState(0);
+ const [completedSteps, setCompletedSteps] = React.useState([]);
+ const [allSteps, setAllSteps] = React.useState([]);
+
+ useEffect(() => {
+ if (!user) {
+ router.push('/login');
+ return;
+ }
+ async function fetchCompletion() {
+ setCompletionLoading(true);
+ const progress = await getProfileCompletion();
+ // progress can be percent or object
+ if (progress && typeof progress === 'object') {
+ setProgressPercent(progress.progressPercent ?? 0);
+ setCompletedSteps(progress.completedSteps ?? []);
+ setAllSteps(progress.steps?.map((s: any) => s.name || s.title || '') ?? []);
+ } else if (typeof progress === 'number') {
+ setProgressPercent(progress);
+ }
+ setCompletionLoading(false);
+ }
+ fetchCompletion();
+ }, [user, router, refreshKey]);
+
+ // Use API profile data if available, fallback to mock
+ const profileData = React.useMemo(() => {
+ if (!profileDataApi) {
+ return {
+ firstName: 'Admin',
+ lastName: 'User',
+ email: user.email || 'office@profit-planet.com',
+ phone: '+49 123 456 789',
+ address: 'Musterstraße 123, 12345 Berlin',
+ joinDate: 'Oktober 2024',
+ memberStatus: 'Gold Member',
+ profileComplete: progressPercent,
+ accountHolder: '', // Always empty string if not provided
+ iban: '',
+ };
+ }
+ const { user: apiUser = {}, profile: apiProfile = {}, userStatus = {} } = profileDataApi;
+ return {
+ firstName: apiUser.firstName ?? apiProfile.first_name ?? '',
+ lastName: apiUser.lastName ?? apiProfile.last_name ?? '',
+ email: apiUser.email ?? '',
+ phone: apiUser.phone ?? apiProfile.phone ?? '',
+ address: apiProfile.address ?? '',
+ joinDate: apiUser.createdAt
+ ? new Date(apiUser.createdAt).toLocaleDateString('de-DE', { year: 'numeric', month: 'long' })
+ : '',
+ memberStatus: userStatus.status ?? '',
+ profileComplete: progressPercent,
+ accountHolder: apiProfile.account_holder_name ?? '', // Only use account_holder_name
+ iban: apiUser.iban ?? '',
+ };
+ }, [profileDataApi, user, progressPercent]);
// Dummy data for new sections
- const documents = [
- { id: 1, name: 'Passport.pdf', type: 'PDF', uploaded: '2024-05-01' },
- { id: 2, name: 'Invoice_2024.xlsx', type: 'Excel', uploaded: '2024-06-10' },
- { id: 3, name: 'ProfilePhoto.jpg', type: 'Image', uploaded: '2024-04-15' },
- ]
+ const documents = Array.isArray(mediaData?.documents) ? mediaData.documents : [];
+ // Adjusted bankInfo state to only have accountHolder and iban, always strings
const [bankInfo, setBankInfo] = React.useState({
- accountHolder: 'Admin User',
- iban: 'DE89 3704 0044 0532 0130 00',
- bic: 'COBADEFFXXX',
- bankName: 'Commerzbank',
- })
- const [editingBank, setEditingBank] = React.useState(false)
+ accountHolder: '',
+ iban: '',
+ });
+ const [editingBank, setEditingBank] = React.useState(false);
const [bankDraft, setBankDraft] = React.useState(bankInfo)
- const matrices = [
- { id: 1, name: 'Starter Matrix', level: '1', status: 'Active', joined: '2024-03-01' },
- { id: 2, name: 'Gold Matrix', level: '2', status: 'Pending', joined: '2024-05-15' },
- { id: 3, name: 'Platinum Matrix', level: '3', status: 'Active', joined: '2024-06-01' },
- ]
+ // Modal state
+ const [editModalOpen, setEditModalOpen] = React.useState(false);
+ const [editModalType, setEditModalType] = React.useState<'basic' | 'bank'>('basic');
+ const [editModalValues, setEditModalValues] = React.useState>({});
+
+ // Modal error state
+ const [editModalError, setEditModalError] = React.useState(null);
+
+ // Modal field definitions
+ const basicFields = [
+ { key: 'firstName', label: 'First Name' },
+ { key: 'lastName', label: 'Last Name' },
+ { key: 'email', label: 'Email Address', type: 'email' },
+ { key: 'phone', label: 'Phone Number' },
+ { key: 'address', label: 'Address' },
+ ];
+ const bankFields = [
+ { key: 'accountHolder', label: 'Account Holder' },
+ { key: 'iban', label: 'IBAN' },
+ ];
+
+ // Modal open handlers
+ function openEditModal(type: 'basic' | 'bank', values: Record) {
+ setEditModalType(type);
+ setEditModalValues(values);
+ setEditModalOpen(true);
+ }
+
+ // Modal save handler (calls API)
+ async function handleEditModalSave() {
+ setEditModalError(null);
+ if (editModalType === 'basic') {
+ const payload: Partial = {};
+ (['firstName', 'lastName', 'email', 'phone', 'address'] as const).forEach(key => {
+ if (editModalValues[key] !== getProfileField(profileData, key)) {
+ payload[key] = editModalValues[key]?.trim();
+ }
+ });
+ const res = await editProfileBasic(payload);
+ if (res.success) {
+ setEditModalOpen(false);
+ // Start smooth refresh with overlay spinner
+ setShowRefreshing(true);
+ setRefreshKey(k => k + 1);
+ } else if (res.status === 409) {
+ setEditModalError('Email already in use.');
+ } else if (res.status === 401) {
+ router.push('/login');
+ } else {
+ setEditModalError(res.error || 'Failed to update profile.');
+ }
+ } else {
+ const payload: Partial = {};
+ (['accountHolder', 'iban'] as const).forEach(key => {
+ if (editModalValues[key] !== getProfileField(profileData, key)) {
+ payload[key] = editModalValues[key]?.trim();
+ }
+ });
+ const res = await editProfileBank(payload);
+ if (res.success) {
+ setBankInfo({
+ accountHolder: res.data?.profile?.account_holder_name ?? '',
+ iban: res.data?.user?.iban ?? '',
+ });
+ setEditModalOpen(false);
+ // Start smooth refresh with overlay spinner
+ setShowRefreshing(true);
+ setRefreshKey(k => k + 1);
+ } else if (res.status === 400 && res.error?.toLowerCase().includes('iban')) {
+ setEditModalError('Invalid IBAN.');
+ } else if (res.status === 401) {
+ router.push('/login');
+ } else {
+ setEditModalError(res.error || 'Failed to update bank info.');
+ }
+ }
+ }
+
+ // Modal change handler
+ function handleEditModalChange(key: string, value: string) {
+ setEditModalValues(prev => ({ ...prev, [key]: value }));
+ }
+
+ // Hide overlay when all data re-fetches complete
+ useEffect(() => {
+ if (showRefreshing && !profileLoading && !mediaLoading && !completionLoading) {
+ const t = setTimeout(() => setShowRefreshing(false), 200); // small delay for smoothness
+ return () => clearTimeout(t);
+ }
+ }, [showRefreshing, profileLoading, mediaLoading, completionLoading]);
return (
@@ -84,90 +271,28 @@ export default function ProfilePage() {
- {/* 1. Profile Completion */}
-
-
-
Profile Completion
- {profileData.profileComplete}%
-
-
-
- Complete your profile to unlock all features
-
-
+ {/* Profile Completion Progress Bar */}
+
- {/* 2. Basic Info + Sidebar */}
+ {/* Basic Info + Sidebar */}
{/* Basic Information */}
-
-
-
Basic Information
-
-
-
-
-
-
-
-
-
- {profileData.firstName}
-
-
-
-
-
-
- {profileData.lastName}
-
-
-
-
-
-
-
-
- {profileData.email}
-
-
-
-
-
-
-
-
-
{profileData.phone}
-
-
-
-
-
-
-
- {profileData.address}
-
-
-
-
+
openEditModal('basic', {
+ firstName: profileData.firstName,
+ lastName: profileData.lastName,
+ email: profileData.email,
+ phone: profileData.phone,
+ address: profileData.address,
+ })}
+ />
{/* Sidebar: Account Status + Quick Actions */}
@@ -216,164 +341,27 @@ export default function ProfilePage() {
- {/* 3. Media, Bank Info, Matrix Overview */}
+ {/* Bank Info, Media */}
- {/* --- Media Section --- */}
-
-
Media & Documents
-
-
-
-
- | Name |
- Type |
- Uploaded |
- |
-
-
-
- {documents.map(doc => (
-
- | {doc.name} |
- {doc.type} |
- {doc.uploaded} |
-
-
-
- |
-
- ))}
-
-
-
-
{/* --- Edit Bank Information Section --- */}
-
-
-
Bank Information
- {!editingBank && (
-
- )}
-
-
-
- {/* --- Matrix Overview Section --- */}
-
-
Matrix Overview
-
-
-
-
- | Matrix Name |
- Level |
- Status |
- Joined |
- |
-
-
-
- {matrices.map(matrix => (
-
- | {matrix.name} |
- {matrix.level} |
-
-
- {matrix.status}
-
- |
- {matrix.joined} |
-
-
- |
-
- ))}
-
-
-
-
+
openEditModal('bank', {
+ accountHolder: profileData.accountHolder,
+ iban: profileData.iban,
+ })}
+ />
+ {/* --- Media Section --- */}
+
- {/* 4. Account Settings */}
+ {/* Account Settings */}
Account Settings
@@ -413,6 +401,32 @@ export default function ProfilePage() {
+
+ {/* Global refreshing overlay */}
+ {showRefreshing && (
+
+ )}
+
+ {/* Edit Modal */}
+
{ setEditModalOpen(false); setEditModalError(null); }}
+ >
+ {/* Show error message if present */}
+ {editModalError && (
+ {editModalError}
+ )}
+
)
}
\ No newline at end of file