11"use client"
22
33import * as React from "react"
4+ import { signOut } from "next-auth/react"
45import { Button } from "@/components/ui/button"
56import { Card , CardContent } from "@/components/ui/card"
67import { Input } from "@/components/ui/input"
@@ -15,6 +16,7 @@ export default function Page() {
1516 const [ saving , setSaving ] = React . useState ( false )
1617 const [ orgId , setOrgId ] = React . useState < string | null > ( null )
1718 const [ orgEmail , setOrgEmail ] = React . useState < string > ( "" )
19+ const [ orgContactEmail , setOrgContactEmail ] = React . useState < string > ( "" )
1820 const [ userEmail , setUserEmail ] = React . useState < string > ( "" )
1921 const [ members , setMembers ] = React . useState < Array < { id : string ; user : { id : string ; name : string | null ; email : string ; image : string | null } } > > ( [ ] )
2022 const [ pending , setPending ] = React . useState < Array < { id : string ; message : string | null ; createdAt : string ; user : { id : string ; name : string | null ; email : string ; image : string | null } } > > ( [ ] )
@@ -42,6 +44,7 @@ export default function Page() {
4244 const [ defaultLocation , setDefaultLocation ] = React . useState < string > ( "" )
4345 const [ defaultHours , setDefaultHours ] = React . useState < number | undefined > ( 2 )
4446 const [ defaultVolunteers , setDefaultVolunteers ] = React . useState < number | undefined > ( 10 )
47+ const [ deleting , setDeleting ] = React . useState ( false )
4548
4649 // Simple option lists; can be expanded
4750 const timezones = React . useMemo ( ( ) => {
@@ -71,6 +74,7 @@ export default function Page() {
7174 setOrgName ( json ?. name ?? "" )
7275 if ( json ?. id ) setOrgId ( json . id as string )
7376 setOrgEmail ( ( json ?. email as string ) || "" )
77+ setOrgContactEmail ( ( json ?. contactEmail as string ) || "" )
7478 setUserEmail ( ( json ?. userEmail as string ) || "" )
7579 // baseUrl no longer used
7680 setTimezone ( ( prev ) => ( json ?. timezone as string ) || prev )
@@ -351,12 +355,33 @@ export default function Page() {
351355 < p className = "text-sm text-muted-foreground" > Export a full JSON snapshot of your data.</ p >
352356 </ div >
353357 < div className = "shrink-0" >
354- < Button
355- className = "bg-orange-500 text-white hover:bg-orange-600 disabled:opacity-50 disabled:pointer-events-none"
356- disabled
357- >
358- Export as JSON
359- </ Button >
358+ { ( ( ) => {
359+ const isOwner = Boolean ( userEmail ) && ( userEmail === orgEmail || ( ! ! orgContactEmail && userEmail === orgContactEmail ) )
360+ const disabled = loading || saving || ! isOwner
361+ return (
362+ < Button
363+ className = "bg-orange-500 text-white hover:bg-orange-600 disabled:opacity-50 disabled:pointer-events-none"
364+ disabled = { disabled }
365+ onClick = { async ( ) => {
366+ try {
367+ const r = await fetch ( "/api/org/export?type=account" )
368+ if ( ! r . ok ) return
369+ const blob = await r . blob ( )
370+ const url = URL . createObjectURL ( blob )
371+ const a = document . createElement ( "a" )
372+ a . href = url
373+ a . download = `organization-${ orgId || "account" } .json`
374+ document . body . appendChild ( a )
375+ a . click ( )
376+ a . remove ( )
377+ URL . revokeObjectURL ( url )
378+ } catch { }
379+ } }
380+ >
381+ Export as JSON
382+ </ Button >
383+ )
384+ } ) ( ) }
360385 </ div >
361386 </ div >
362387 </ CardContent >
@@ -371,14 +396,67 @@ export default function Page() {
371396 < p className = "text-sm text-muted-foreground" > Be careful—this action is permanent.</ p >
372397 </ div >
373398 < div className = "shrink-0" >
374- < Button
375- variant = "destructive"
376- disabled
377- className = "disabled:opacity-50 disabled:pointer-events-none"
378- title = "Temporarily disabled"
379- >
380- Delete organization (disabled)
381- </ Button >
399+ { ( ( ) => {
400+ const isOwner = Boolean ( userEmail ) && ( userEmail === orgEmail || ( ! ! orgContactEmail && userEmail === orgContactEmail ) )
401+ const disabled = loading || saving || deleting
402+ if ( isOwner ) {
403+ return (
404+ < Button
405+ variant = "destructive"
406+ disabled = { disabled }
407+ className = "disabled:opacity-50 disabled:pointer-events-none"
408+ title = "Delete this organization"
409+ onClick = { async ( ) => {
410+ const confirmed = window . confirm ( "This will permanently delete the organization and all related data. Continue?" )
411+ if ( ! confirmed ) return
412+ try {
413+ setDeleting ( true )
414+ const r = await fetch ( "/api/org/delete" , { method : "DELETE" } )
415+ if ( ! r . ok ) {
416+ alert ( "Failed to delete organization" )
417+ return
418+ }
419+ await signOut ( { callbackUrl : "/" } )
420+ } catch {
421+ alert ( "Failed to delete organization" )
422+ } finally {
423+ setDeleting ( false )
424+ }
425+ } }
426+ >
427+ { deleting ? "Deleting…" : "Delete organization" }
428+ </ Button >
429+ )
430+ }
431+ // Non-owner: allow deleting their own account
432+ return (
433+ < Button
434+ variant = "destructive"
435+ disabled = { disabled }
436+ className = "disabled:opacity-50 disabled:pointer-events-none"
437+ title = "Delete my account"
438+ onClick = { async ( ) => {
439+ const confirmed = window . confirm ( "This will permanently delete your account and remove your access to this org. Continue?" )
440+ if ( ! confirmed ) return
441+ try {
442+ setDeleting ( true )
443+ const r = await fetch ( "/api/user/deactivate" , { method : "DELETE" } )
444+ if ( ! r . ok ) {
445+ alert ( "Failed to delete account" )
446+ return
447+ }
448+ await signOut ( { callbackUrl : "/" } )
449+ } catch {
450+ alert ( "Failed to delete account" )
451+ } finally {
452+ setDeleting ( false )
453+ }
454+ } }
455+ >
456+ { deleting ? "Deleting…" : "Delete my account" }
457+ </ Button >
458+ )
459+ } ) ( ) }
382460 </ div >
383461 </ div >
384462 </ CardContent >
0 commit comments