feat: add account data download functionality to profile page
This commit is contained in:
parent
51cffc0ad5
commit
e01dbb6405
@ -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>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user