(user) add "met personally" badge

This commit is contained in:
Andrea Vos 2025-09-02 09:33:17 +02:00
parent 7b5a574260
commit 4198c09918
7 changed files with 43 additions and 4 deletions

View File

@ -6,6 +6,7 @@ import { buildFlags } from '#shared/flags.ts';
import { buildImageUrl } from '#shared/helpers.ts'; import { buildImageUrl } from '#shared/helpers.ts';
import type { Profile, UserWithProfiles } from '#shared/profile.ts'; import type { Profile, UserWithProfiles } from '#shared/profile.ts';
import useConfig from '~/composables/useConfig.ts'; import useConfig from '~/composables/useConfig.ts';
import useDialogue from '~/composables/useDialogue';
import useMainPronoun from '~/composables/useMainPronoun.ts'; import useMainPronoun from '~/composables/useMainPronoun.ts';
import useSpelling from '~/composables/useSpelling.ts'; import useSpelling from '~/composables/useSpelling.ts';
import { loadCalendar, loadPronounLibrary } from '~/src/data.ts'; import { loadCalendar, loadPronounLibrary } from '~/src/data.ts';
@ -23,6 +24,7 @@ const props = withDefaults(defineProps<{
const { $translator: translator } = useNuxtApp(); const { $translator: translator } = useNuxtApp();
const { convertName } = useSpelling(); const { convertName } = useSpelling();
const config = useConfig(); const config = useConfig();
const dialogue = useDialogue();
const pronounLibrary = await loadPronounLibrary(config); const pronounLibrary = await loadPronounLibrary(config);
@ -87,11 +89,24 @@ const usedOpinions = computed(() => {
<h2> <h2>
@{{ user.username }} @{{ user.username }}
</h2> </h2>
<p v-if="user.team || profile.teamName || profile.footerName" class="mb-2"> <p v-if="user.team || profile.teamName || profile.footerName || user.personally" class="mb-2">
<nuxt-link :to="{ name: 'team' }" class="badge bg-primary text-white"> <nuxt-link
v-if="user.team || profile.teamName || profile.footerName"
:to="{ name: 'team' }"
class="badge bg-primary text-white"
>
<Icon v="collective-logo.svg" class="inverted" /> <Icon v="collective-logo.svg" class="inverted" />
<T>contact.team.member</T> <T>contact.team.member</T>
</nuxt-link> </nuxt-link>
<a
v-if="user.personally"
href="#"
class="badge bg-info text-dark"
@click.prevent="dialogue.alert($t('user.personally.description'))"
>
<Icon v="handshake-alt" />
<T>user.personally.badge</T>
</a>
</p> </p>
</div> </div>
</div> </div>

View File

@ -917,6 +917,9 @@ user:
Your account was created using a method that didn't share a verified email address with us. Your account was created using a method that didn't share a verified email address with us.
Please change the placeholder below to your email and confirm it with a code Please change the placeholder below to your email and confirm it with a code
this way you'll have a fallback login method in case you lose access to the one you used. this way you'll have a fallback login method in case you lose access to the one you used.
personally:
badge: 'Met us in person'
description: 'If you''ve met the team at a pride event or a workshop, reach out via email or our community discord to get a badge.'
profile: profile:
description: 'Description' description: 'Description'

View File

@ -1558,6 +1558,9 @@ user:
Twoje konto zostało utworzone z użyciem metody logowania, która nie udostępniła nam zweryfikowanego adresu email. Twoje konto zostało utworzone z użyciem metody logowania, która nie udostępniła nam zweryfikowanego adresu email.
Aby mieć dostępny zapasowy sposób logowania, gdybyś straciłx dostęp do obecnego, Aby mieć dostępny zapasowy sposób logowania, gdybyś straciłx dostęp do obecnego,
wpisz swój adres email poniżej i potwierdź go kodem. wpisz swój adres email poniżej i potwierdź go kodem.
personally:
badge: 'Poznałx nas w realu'
description: 'Jeśli poznałxś osoby członkowskie kolektywu na wydarzeniu pridowym albo warsztatach, daj nam znać przez maila albo na naszym discordzie społeczności, aby otrzymać odznakę.'
profile: profile:
description: 'Opis' description: 'Opis'

View File

@ -0,0 +1,6 @@
-- Up
ALTER TABLE users ADD COLUMN personally INT DEFAULT 0;
-- Down

View File

@ -588,11 +588,16 @@ router.get('/profile/get/:username', handleErrorAsync(async (req, res) => {
users.bannedReason, users.bannedReason,
users.bannedTerms, users.bannedTerms,
users.bannedBy, users.bannedBy,
users.roles NOT IN ('', '*-external') AS team users.roles NOT IN ('', '*-external') AS team,
users.personally
FROM users FROM users
WHERE users.usernameNorm = ${normalise(req.params.username)} WHERE users.usernameNorm = ${normalise(req.params.username)}
`); `);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
return await fetchProfilesRoute(req, res, locale, user as User); return await fetchProfilesRoute(req, res, locale, user as User);
})); }));
@ -608,11 +613,16 @@ router.get('/profile/get-id/:id', handleErrorAsync(async (req, res) => {
users.bannedReason, users.bannedReason,
users.bannedTerms, users.bannedTerms,
users.bannedBy, users.bannedBy,
users.roles NOT IN ('', '*-external') AS team users.roles NOT IN ('', '*-external') AS team,
users.personally
FROM users FROM users
WHERE users.id = ${req.params.id} WHERE users.id = ${req.params.id}
`); `);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
return await fetchProfilesRoute(req, res, locale, user as User); return await fetchProfilesRoute(req, res, locale, user as User);
})); }));

View File

@ -60,6 +60,7 @@ export interface UserRow {
loginAttempts: string | null; loginAttempts: string | null;
timesheets: string | null; timesheets: string | null;
socialLookup: number; socialLookup: number;
personally: 0 | 1;
} }
export interface AuthenticatorRow { export interface AuthenticatorRow {

View File

@ -12,6 +12,7 @@ export interface UserWithProfiles {
bannedBy: string | null; bannedBy: string | null;
team: string; team: string;
profiles: Record<string, Profile>; profiles: Record<string, Profile>;
personally: 0 | 1;
} }
export interface Profile { export interface Profile {