Improve invitation UI and fix access removal
- Move role selector (Caretaker/Guardian) above email input in Access screen - Remove "(view only)" suffix from Caretaker role in email templates - Remove "expires in 7 days" text from invitation emails - Remove expires_at field from invitation creation (invitations never expire) - Fix deletion of accepted invitations (now also removes user_access record) - Add favicon to accept-invite.html page
This commit is contained in:
parent
d9fcdf1751
commit
f4ff281bcc
@ -324,32 +324,7 @@ export default function ShareAccessScreen() {
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Invite Someone</Text>
|
||||
|
||||
<View style={styles.inputRow}>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Email address"
|
||||
placeholderTextColor={AppColors.textMuted}
|
||||
value={email}
|
||||
onChangeText={setEmail}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
keyboardType="email-address"
|
||||
editable={!isLoading}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
style={[styles.sendButton, isLoading && styles.sendButtonDisabled]}
|
||||
onPress={handleSendInvite}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
<ActivityIndicator size="small" color={AppColors.white} />
|
||||
) : (
|
||||
<Ionicons name="send" size={18} color={AppColors.white} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Role Toggle */}
|
||||
{/* Role Toggle - above email */}
|
||||
<View style={styles.roleToggle}>
|
||||
<TouchableOpacity
|
||||
style={[styles.roleButton, role === 'caretaker' && styles.roleButtonActive]}
|
||||
@ -374,6 +349,31 @@ export default function ShareAccessScreen() {
|
||||
? 'Can view activity and chat with Julia'
|
||||
: 'Full access: edit info, manage subscription'}
|
||||
</Text>
|
||||
|
||||
<View style={[styles.inputRow, { marginTop: Spacing.md }]}>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Email address"
|
||||
placeholderTextColor={AppColors.textMuted}
|
||||
value={email}
|
||||
onChangeText={setEmail}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
keyboardType="email-address"
|
||||
editable={!isLoading}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
style={[styles.sendButton, isLoading && styles.sendButtonDisabled]}
|
||||
onPress={handleSendInvite}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
<ActivityIndicator size="small" color={AppColors.white} />
|
||||
) : (
|
||||
<Ionicons name="send" size={18} color={AppColors.white} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* People with Access */}
|
||||
|
||||
@ -310,9 +310,7 @@ router.post('/', async (req, res) => {
|
||||
attempts++;
|
||||
}
|
||||
|
||||
// Create invitation (expires in 7 days)
|
||||
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
|
||||
|
||||
// Create invitation (no expiry)
|
||||
const { data: invitation, error } = await supabase
|
||||
.from('invitations')
|
||||
.insert({
|
||||
@ -321,8 +319,7 @@ router.post('/', async (req, res) => {
|
||||
token: inviteToken,
|
||||
role: role,
|
||||
email: email?.toLowerCase() || null,
|
||||
label: label || null,
|
||||
expires_at: expiresAt.toISOString()
|
||||
label: label || null
|
||||
})
|
||||
.select()
|
||||
.single();
|
||||
@ -690,8 +687,13 @@ router.delete('/:id', async (req, res) => {
|
||||
return res.status(404).json({ error: 'Invitation not found' });
|
||||
}
|
||||
|
||||
if (invitation.accepted_at) {
|
||||
return res.status(400).json({ error: 'Cannot revoke accepted invitation' });
|
||||
// If invitation was accepted, also remove user_access
|
||||
if (invitation.accepted_by) {
|
||||
await supabase
|
||||
.from('user_access')
|
||||
.delete()
|
||||
.eq('beneficiary_id', invitation.beneficiary_id)
|
||||
.eq('accessor_id', invitation.accepted_by);
|
||||
}
|
||||
|
||||
// Delete invitation
|
||||
|
||||
@ -222,7 +222,7 @@ If you didn't request this code, you can safely ignore this email.
|
||||
async function sendInvitationEmail({ email, inviterName, beneficiaryName, role, inviteCode }) {
|
||||
const frontendUrl = process.env.FRONTEND_URL || 'https://wellnuo.smartlaunchhub.com';
|
||||
const acceptLink = `${frontendUrl}/accept-invite.html?code=${inviteCode}`;
|
||||
const roleText = role === 'guardian' ? 'Guardian (full access)' : 'Caretaker (view only)';
|
||||
const roleText = role === 'guardian' ? 'Guardian' : 'Caretaker';
|
||||
|
||||
const htmlContent = `
|
||||
<!DOCTYPE html>
|
||||
@ -276,9 +276,6 @@ async function sendInvitationEmail({ email, inviterName, beneficiaryName, role,
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p style="margin: 24px 0 0 0; font-size: 13px; color: #999999; text-align: center;">
|
||||
This invitation expires in 7 days.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@ -310,8 +307,6 @@ Your invitation code: ${inviteCode}
|
||||
|
||||
Accept your invitation: ${acceptLink}
|
||||
|
||||
This invitation expires in 7 days.
|
||||
|
||||
If you didn't expect this invitation, you can safely ignore this email.
|
||||
|
||||
WellNuo - Elderly Care Monitoring
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Accept Invitation - WellNuo</title>
|
||||
<link rel="icon" type="image/png" href="/favicon.png">
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user