Sync dev changes into release-1.0
This commit is contained in:
@@ -10,12 +10,25 @@ type ProfileInfo = {
|
||||
auth_provider: string
|
||||
}
|
||||
|
||||
type ContactInfo = {
|
||||
email?: string | null
|
||||
discord?: string | null
|
||||
telegram?: string | null
|
||||
matrix?: string | null
|
||||
}
|
||||
|
||||
export default function ProfilePage() {
|
||||
const router = useRouter()
|
||||
const [profile, setProfile] = useState<ProfileInfo | null>(null)
|
||||
const [contact, setContact] = useState<ContactInfo>({})
|
||||
const [currentPassword, setCurrentPassword] = useState('')
|
||||
const [newPassword, setNewPassword] = useState('')
|
||||
const [status, setStatus] = useState<string | null>(null)
|
||||
const [contactStatus, setContactStatus] = useState<string | null>(null)
|
||||
const [referrals, setReferrals] = useState<
|
||||
{ code: string; uses_count?: number; max_uses?: number | null }[]
|
||||
>([])
|
||||
const [referralStatus, setReferralStatus] = useState<string | null>(null)
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -38,6 +51,23 @@ export default function ProfilePage() {
|
||||
role: data?.role ?? 'user',
|
||||
auth_provider: data?.auth_provider ?? 'local',
|
||||
})
|
||||
const contactResponse = await authFetch(`${baseUrl}/auth/contact`)
|
||||
if (contactResponse.ok) {
|
||||
const contactData = await contactResponse.json()
|
||||
setContact({
|
||||
email: contactData?.contact?.email ?? '',
|
||||
discord: contactData?.contact?.discord ?? '',
|
||||
telegram: contactData?.contact?.telegram ?? '',
|
||||
matrix: contactData?.contact?.matrix ?? '',
|
||||
})
|
||||
}
|
||||
const referralResponse = await authFetch(`${baseUrl}/auth/referrals`)
|
||||
if (referralResponse.ok) {
|
||||
const referralData = await referralResponse.json()
|
||||
if (Array.isArray(referralData?.invites)) {
|
||||
setReferrals(referralData.invites)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
setStatus('Could not load your profile.')
|
||||
@@ -78,6 +108,55 @@ export default function ProfilePage() {
|
||||
}
|
||||
}
|
||||
|
||||
const submitContact = async (event: React.FormEvent) => {
|
||||
event.preventDefault()
|
||||
setContactStatus(null)
|
||||
try {
|
||||
const baseUrl = getApiBase()
|
||||
const response = await authFetch(`${baseUrl}/auth/contact`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
email: contact.email,
|
||||
discord: contact.discord,
|
||||
telegram: contact.telegram,
|
||||
matrix: contact.matrix,
|
||||
}),
|
||||
})
|
||||
if (!response.ok) {
|
||||
const text = await response.text()
|
||||
throw new Error(text || 'Update failed')
|
||||
}
|
||||
setContactStatus('Contact details saved.')
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
setContactStatus('Could not update contact details.')
|
||||
}
|
||||
}
|
||||
|
||||
const createReferral = async () => {
|
||||
setReferralStatus(null)
|
||||
try {
|
||||
const baseUrl = getApiBase()
|
||||
const response = await authFetch(`${baseUrl}/auth/referrals`, { method: 'POST' })
|
||||
if (!response.ok) {
|
||||
const text = await response.text()
|
||||
throw new Error(text || 'Could not create referral invite')
|
||||
}
|
||||
const data = await response.json()
|
||||
if (data?.code) {
|
||||
setReferrals((current) => [
|
||||
{ code: data.code, uses_count: 0, max_uses: 1 },
|
||||
...current,
|
||||
])
|
||||
}
|
||||
setReferralStatus('Referral invite created.')
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
setReferralStatus('Could not create a referral invite.')
|
||||
}
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return <main className="card">Loading profile...</main>
|
||||
}
|
||||
@@ -121,6 +200,82 @@ export default function ProfilePage() {
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
<form onSubmit={submitContact} className="auth-form">
|
||||
<h2>Contact details</h2>
|
||||
<label>
|
||||
Email address
|
||||
<input
|
||||
type="email"
|
||||
value={contact.email || ''}
|
||||
onChange={(event) => setContact((current) => ({ ...current, email: event.target.value }))}
|
||||
autoComplete="email"
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
Discord handle
|
||||
<input
|
||||
type="text"
|
||||
value={contact.discord || ''}
|
||||
onChange={(event) =>
|
||||
setContact((current) => ({ ...current, discord: event.target.value }))
|
||||
}
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
Telegram ID
|
||||
<input
|
||||
type="text"
|
||||
value={contact.telegram || ''}
|
||||
onChange={(event) =>
|
||||
setContact((current) => ({ ...current, telegram: event.target.value }))
|
||||
}
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
Matrix ID
|
||||
<input
|
||||
type="text"
|
||||
value={contact.matrix || ''}
|
||||
onChange={(event) =>
|
||||
setContact((current) => ({ ...current, matrix: event.target.value }))
|
||||
}
|
||||
/>
|
||||
</label>
|
||||
{contactStatus && <div className="status-banner">{contactStatus}</div>}
|
||||
<div className="auth-actions">
|
||||
<button type="submit">Save contact details</button>
|
||||
</div>
|
||||
</form>
|
||||
<section className="summary-card">
|
||||
<h2>Referral invites</h2>
|
||||
<p className="meta">
|
||||
Share a referral invite with friends or family. Each invite has limited uses.
|
||||
</p>
|
||||
{referralStatus && <div className="status-banner">{referralStatus}</div>}
|
||||
<div className="auth-actions">
|
||||
<button type="button" onClick={createReferral}>
|
||||
Create referral invite
|
||||
</button>
|
||||
</div>
|
||||
{referrals.length === 0 ? (
|
||||
<div className="meta">No referral invites yet.</div>
|
||||
) : (
|
||||
<div className="cache-table">
|
||||
<div className="cache-row cache-head">
|
||||
<span>Code</span>
|
||||
<span>Uses</span>
|
||||
</div>
|
||||
{referrals.map((invite) => (
|
||||
<div key={invite.code} className="cache-row">
|
||||
<span>{invite.code}</span>
|
||||
<span>
|
||||
{invite.uses_count ?? 0}/{invite.max_uses ?? '∞'}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user