feat: add account data download functionality to profile page

This commit is contained in:
seaznCode 2026-01-23 18:13:16 +01:00
parent 51cffc0ad5
commit e01dbb6405

View File

@ -15,6 +15,7 @@ import { getProfileCompletion } from './hooks/getProfileCompletion'
import { useProfileData } from './hooks/getProfileData' import { useProfileData } from './hooks/getProfileData'
import { useMedia } from './hooks/getMedia' import { useMedia } from './hooks/getMedia'
import { editProfileBasic } from './hooks/editProfile' import { editProfileBasic } from './hooks/editProfile'
import { authFetch } from '../utils/authFetch'
// Helper to display missing fields in subtle gray italic (no yellow highlight) // Helper to display missing fields in subtle gray italic (no yellow highlight)
function HighlightIfMissing({ value, children }: { value: any, children: React.ReactNode }) { function HighlightIfMissing({ value, children }: { value: any, children: React.ReactNode }) {
@ -65,6 +66,8 @@ const bankFields = [
{ key: 'iban', label: 'IBAN', type: 'text' }, { key: 'iban', label: 'IBAN', type: 'text' },
]; ];
const BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001'
export default function ProfilePage() { export default function ProfilePage() {
const router = useRouter() const router = useRouter()
const user = useAuthStore(state => state.user) const user = useAuthStore(state => state.user)
@ -91,6 +94,8 @@ export default function ProfilePage() {
const [editModalType, setEditModalType] = React.useState<'basic' | 'bank'>('basic') const [editModalType, setEditModalType] = React.useState<'basic' | 'bank'>('basic')
const [editModalValues, setEditModalValues] = React.useState<Record<string, string>>({}) const [editModalValues, setEditModalValues] = React.useState<Record<string, string>>({})
const [editModalError, setEditModalError] = React.useState<string | null>(null) const [editModalError, setEditModalError] = React.useState<string | null>(null)
const [downloadLoading, setDownloadLoading] = React.useState(false)
const [downloadError, setDownloadError] = React.useState<string | null>(null)
useEffect(() => { setHasHydrated(true) }, []) useEffect(() => { setHasHydrated(true) }, [])
@ -221,6 +226,65 @@ export default function ProfilePage() {
setEditModalValues(prev => ({ ...prev, [key]: value })) setEditModalValues(prev => ({ ...prev, [key]: value }))
} }
async function handleDownloadAccountData() {
if (!userId) return
setDownloadError(null)
setDownloadLoading(true)
try {
const fullRes = await authFetch(`${BASE_URL}/api/users/${userId}/full`, { method: 'GET' })
if (fullRes.status === 401) {
router.push('/login')
return
}
if (!fullRes.ok) {
throw new Error('Failed to fetch account data')
}
const fullData = await fullRes.json()
const statusOnly = fullData?.userStatus?.status ?? null
const cleanedUser = fullData?.user && typeof fullData.user === 'object'
? (() => {
const { id, user_id, ...rest } = fullData.user as Record<string, any>
return rest
})()
: fullData?.user
const cleanedProfile = fullData?.profile && typeof fullData.profile === 'object'
? (() => {
const { id, user_id, ...rest } = fullData.profile as Record<string, any>
return rest
})()
: fullData?.profile
const exportPayload = {
exportedAt: new Date().toISOString(),
userType: user?.userType || null,
account: {
success: fullData?.success ?? true,
user: cleanedUser,
profile: cleanedProfile,
userStatus: statusOnly
}
}
const blob = new Blob([JSON.stringify(exportPayload, null, 2)], { type: 'application/json' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `profit-planet-account-data-${userId}-${new Date().toISOString().slice(0, 10)}.json`
document.body.appendChild(a)
a.click()
a.remove()
URL.revokeObjectURL(url)
} catch (error: any) {
setDownloadError(error?.message || 'Failed to download account data.')
} finally {
setDownloadLoading(false)
}
}
// --- EARLY RETURN AFTER ALL HOOKS --- // --- EARLY RETURN AFTER ALL HOOKS ---
if (!hasHydrated || !isAuthReady || !user) { if (!hasHydrated || !isAuthReady || !user) {
return ( return (
@ -309,13 +373,20 @@ export default function ProfilePage() {
> >
Go to Dashboard Go to Dashboard
</button> </button>
<button className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 rounded-lg transition-colors"> <button
Download Account Data onClick={handleDownloadAccountData}
disabled={downloadLoading}
className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 rounded-lg transition-colors disabled:opacity-60 disabled:cursor-not-allowed"
>
{downloadLoading ? 'Preparing download...' : 'Download Account Data'}
</button> </button>
<button className="w-full text-left px-4 py-2 text-sm text-red-600 hover:bg-red-50 rounded-lg transition-colors"> <button className="w-full text-left px-4 py-2 text-sm text-red-600 hover:bg-red-50 rounded-lg transition-colors">
Delete Account Delete Account
</button> </button>
</div> </div>
{downloadError && (
<p className="mt-2 text-xs text-red-600">{downloadError}</p>
)}
</div> </div>
</div> </div>
</div> </div>