Various pre-launch fixes.
This commit is contained in:
parent
246f2023bc
commit
1c3273cee2
9 changed files with 29 additions and 39 deletions
|
|
@ -88,19 +88,7 @@ defineEmits(['edit', 'delete', 'confirm-delete', 'cancel-delete'])
|
|||
|
||||
const { slackUrl } = useBoardChannels()
|
||||
|
||||
const capitalizeAvatar = (str) => {
|
||||
if (str.toLowerCase() === 'wtf') return 'WTF'
|
||||
return str
|
||||
.split('-')
|
||||
.map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
|
||||
.join('-')
|
||||
}
|
||||
|
||||
const authorAvatar = computed(() => {
|
||||
const a = props.post.author?.avatar
|
||||
if (!a) return null
|
||||
return `/ghosties/Ghost-${capitalizeAvatar(a)}.png`
|
||||
})
|
||||
const authorAvatar = computed(() => ghostieImagePath(props.post.author?.avatar))
|
||||
|
||||
const slackHandle = computed(() => props.post.author?.board?.slackHandle || '')
|
||||
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@
|
|||
</dl>
|
||||
</DashedBox>
|
||||
<p class="signup-flow-body" style="margin-top: 16px">
|
||||
Check {{ summary?.email }} for a sign-in link to finish setting up
|
||||
your account. The link expires in 15 minutes.
|
||||
{{ successMessage || `Check ${summary?.email} for a sign-in link to finish setting up your account. The link expires in 15 minutes.` }}
|
||||
</p>
|
||||
</template>
|
||||
|
||||
|
|
@ -62,6 +61,7 @@ const props = defineProps({
|
|||
summary: { type: Object, default: null },
|
||||
errorMessage: { type: String, default: "" },
|
||||
dashboardHref: { type: String, default: "/welcome" },
|
||||
successMessage: { type: String, default: "" },
|
||||
});
|
||||
|
||||
defineEmits(["close"]);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
<NuxtLink to="/member/profile" class="member-link">
|
||||
<img
|
||||
v-if="memberData.avatar"
|
||||
:src="`/ghosties/Ghost-${capitalize(memberData.avatar)}.png`"
|
||||
:src="ghostieImagePath(memberData.avatar)"
|
||||
:alt="memberData.name"
|
||||
class="member-avatar"
|
||||
>
|
||||
|
|
@ -86,11 +86,6 @@ const handleLogout = async () => {
|
|||
navigateTo("/");
|
||||
};
|
||||
|
||||
const capitalize = (str) => {
|
||||
if (!str) return "";
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
};
|
||||
|
||||
const breadcrumbs = computed(() => {
|
||||
if (!props.pagePath) return [];
|
||||
const segments = props.pagePath.split(" / ");
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@
|
|||
:summary="flowSummary"
|
||||
:error-message="errorMessage"
|
||||
dashboard-href="/member/dashboard?welcome=1"
|
||||
success-message="You're signed in. Taking you to your dashboard..."
|
||||
@close="closeFlowOverlay"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
<div class="profile-avatar">
|
||||
<img
|
||||
v-if="member.avatar"
|
||||
:src="`/ghosties/Ghost-${member.avatar.charAt(0).toUpperCase() + member.avatar.slice(1)}.png`"
|
||||
:src="ghostieImagePath(member.avatar)"
|
||||
:alt="member.name"
|
||||
class="profile-avatar-img"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@
|
|||
<div class="mc-avatar">
|
||||
<img
|
||||
v-if="member.avatar"
|
||||
:src="`/ghosties/Ghost-${capitalize(member.avatar)}.png`"
|
||||
:src="ghostieImagePath(member.avatar)"
|
||||
:alt="member.name"
|
||||
class="mc-avatar-img"
|
||||
>
|
||||
|
|
@ -185,14 +185,6 @@ const getInitials = (name) => {
|
|||
.slice(0, 2)
|
||||
}
|
||||
|
||||
const capitalize = (str) => {
|
||||
if (!str) return ''
|
||||
return str
|
||||
.split('-')
|
||||
.map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
|
||||
.join('-')
|
||||
}
|
||||
|
||||
// ---- Computed ----
|
||||
const visibleTagOptions = computed(() =>
|
||||
showAllTags.value ? craftTagOptions.value : craftTagOptions.value.slice(0, 10)
|
||||
|
|
|
|||
15
app/utils/ghostieAvatar.js
Normal file
15
app/utils/ghostieAvatar.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
const AVATAR_FILE_NAMES = {
|
||||
'sweet': 'Sweet',
|
||||
'mild': 'Mild',
|
||||
'exasperated': 'Exasperated',
|
||||
'disbelieving': 'Disbelieving',
|
||||
'double-take': 'Double-Take',
|
||||
'wtf': 'WTF',
|
||||
}
|
||||
|
||||
export function ghostieImagePath(avatar) {
|
||||
if (!avatar) return null
|
||||
const name = AVATAR_FILE_NAMES[String(avatar).toLowerCase()]
|
||||
if (!name) return null
|
||||
return `/ghosties/Ghost-${name}.png`
|
||||
}
|
||||
|
|
@ -68,12 +68,14 @@ export default defineEventHandler(async (event) => {
|
|||
|
||||
await assignMemberNumber(member._id)
|
||||
|
||||
// Update pre-registration
|
||||
// Update pre-registration. Burning the jti here (instead of in verify) keeps
|
||||
// the verify endpoint idempotent so a page refresh doesn't lock the invitee out.
|
||||
await PreRegistration.findByIdAndUpdate(preReg._id, {
|
||||
$set: {
|
||||
status: 'accepted',
|
||||
acceptedAt: new Date(),
|
||||
memberId: member._id,
|
||||
magicLinkJtiUsed: true,
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -27,16 +27,13 @@ export default defineEventHandler(async (event) => {
|
|||
throw createError({ statusCode: 400, statusMessage: 'This invitation has already been accepted' })
|
||||
}
|
||||
|
||||
// Single-use enforcement
|
||||
if (!decoded.jti || decoded.jti !== preReg.magicLinkJti || preReg.magicLinkJtiUsed) {
|
||||
// Match the jti so that re-invite (which rotates the jti) kills old links.
|
||||
// The burn happens in accept.post.js once a Member is created — keeps verify
|
||||
// idempotent so the form survives a refresh.
|
||||
if (!decoded.jti || decoded.jti !== preReg.magicLinkJti) {
|
||||
throw createError({ statusCode: 401, statusMessage: 'Invalid or expired invitation link' })
|
||||
}
|
||||
|
||||
// Burn the token
|
||||
await PreRegistration.findByIdAndUpdate(preReg._id, {
|
||||
$set: { magicLinkJtiUsed: true }
|
||||
})
|
||||
|
||||
return {
|
||||
preRegistrationId: preReg._id,
|
||||
name: preReg.name,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue