-
+
@@ -71,7 +75,7 @@
@@ -85,6 +89,7 @@ import {
ButtonStyled,
Checkbox,
defineMessages,
+ injectNotificationManager,
StyledInput,
useVIntl,
} from '@modrinth/ui'
@@ -120,7 +125,7 @@ const props = defineProps({
sourceCodeUrl: {
type: String,
default:
- 'https://github.com/modrinth/labrinth/blob/main/apps/labrinth/src/routes/internal/flows.rs',
+ 'https://github.com/modrinth/code/blob/main/apps/frontend/src/components/ui/auth/CreateAccount.vue',
},
onCompleteSignUp: {
type: Function,
@@ -165,8 +170,40 @@ const maxBirthDate = computed(() => {
return date.toISOString().slice(0, 10)
})
+const isDateOfBirthMissing = computed(() => props.requiresDob && dateOfBirthModel.value === '')
+
+const isUnder13 = computed(
+ () =>
+ props.requiresDob &&
+ dateOfBirthModel.value !== '' &&
+ dateOfBirthModel.value > maxBirthDate.value,
+)
+
+const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
+function onCompleteSignUpClick() {
+ if (isDateOfBirthMissing.value) {
+ addNotification({
+ title: formatMessage(messages.dateOfBirthRequiredTitle),
+ text: formatMessage(messages.dateOfBirthRequiredText),
+ type: 'warning',
+ })
+ return
+ }
+
+ if (isUnder13.value) {
+ addNotification({
+ title: formatMessage(messages.ageRequirementWarningTitle),
+ text: formatMessage(messages.under13HelperText),
+ type: 'error',
+ })
+ return
+ }
+
+ props.onCompleteSignUp()
+}
+
const messages = defineMessages({
title: {
id: 'auth.create-account.title',
@@ -176,10 +213,26 @@ const messages = defineMessages({
id: 'auth.create-account.date-of-birth.label',
defaultMessage: 'Date of birth',
},
+ dateOfBirthRequiredTitle: {
+ id: 'auth.create-account.date-of-birth.required.title',
+ defaultMessage: 'Date of birth required',
+ },
+ dateOfBirthRequiredText: {
+ id: 'auth.create-account.date-of-birth.required.text',
+ defaultMessage: 'Please enter your date of birth before continuing.',
+ },
over13HelperText: {
id: 'auth.create-account.date-of-birth.over13-helper',
defaultMessage: 'You must be over 13 years old to use Modrinth.',
},
+ under13HelperText: {
+ id: 'auth.create-account.date-of-birth.under13-helper',
+ defaultMessage: 'You cannot create an account at Modrinth unless you are 13 years old.',
+ },
+ ageRequirementWarningTitle: {
+ id: 'auth.create-account.age-requirement.warning-title',
+ defaultMessage: 'Age requirement',
+ },
infoPanelText: {
id: 'auth.create-account.info-panel.text',
defaultMessage:
diff --git a/apps/frontend/src/components/ui/auth/SignUp.vue b/apps/frontend/src/components/ui/auth/SignUp.vue
index 9b46aca712..e12ebd14b1 100644
--- a/apps/frontend/src/components/ui/auth/SignUp.vue
+++ b/apps/frontend/src/components/ui/auth/SignUp.vue
@@ -79,13 +79,6 @@
wrapper-class="w-full"
/>
-
-
@@ -101,17 +94,11 @@
-
-
@@ -147,7 +134,6 @@ import {
} from '@modrinth/assets'
import {
ButtonStyled,
- Checkbox,
commonMessages,
defineMessages,
IntlFormatted,
@@ -156,7 +142,6 @@ import {
} from '@modrinth/ui'
import { computed } from 'vue'
-import HCaptcha from '@/components/ui/auth/HCaptcha.vue'
import { getAuthUrl } from '@/composables/auth.ts'
const props = defineProps({
@@ -172,10 +157,6 @@ const props = defineProps({
type: Object,
default: () => ({}),
},
- globals: {
- type: Object,
- default: null,
- },
email: {
type: String,
default: '',
@@ -184,29 +165,17 @@ const props = defineProps({
type: String,
default: '',
},
- token: {
- type: String,
- default: '',
- },
- subscribe: {
- type: Boolean,
- default: false,
- },
onToggleOtherOptions: {
type: Function,
default: () => {},
},
- onCreateAccount: {
+ onContinueWithEmail: {
type: Function,
default: () => {},
},
- onSetCaptchaRef: {
- type: Function,
- default: undefined,
- },
})
-const emit = defineEmits(['update:email', 'update:password', 'update:token', 'update:subscribe'])
+const emit = defineEmits(['update:email', 'update:password'])
const emailModel = computed({
get: () => props.email,
@@ -218,16 +187,6 @@ const passwordModel = computed({
set: (value) => emit('update:password', value),
})
-const tokenModel = computed({
- get: () => props.token,
- set: (value) => emit('update:token', value),
-})
-
-const subscribeModel = computed({
- get: () => props.subscribe,
- set: (value) => emit('update:subscribe', value),
-})
-
const { formatMessage } = useVIntl()
const messages = defineMessages({
@@ -239,10 +198,6 @@ const messages = defineMessages({
id: 'auth.continue-with-provider',
defaultMessage: 'Continue with {provider}',
},
- subscribeLabel: {
- id: 'auth.sign-up.subscribe.label',
- defaultMessage: 'Subscribe to updates about Modrinth',
- },
legalDisclaimer: {
id: 'auth.sign-up.legal-dislaimer',
defaultMessage:
diff --git a/apps/frontend/src/pages/auth/sign-up.vue b/apps/frontend/src/pages/auth/sign-up.vue
index 5e18477b15..398232da5c 100644
--- a/apps/frontend/src/pages/auth/sign-up.vue
+++ b/apps/frontend/src/pages/auth/sign-up.vue
@@ -1,15 +1,22 @@
+
@@ -24,6 +31,7 @@ import {
} from '@modrinth/ui'
import { useQuery } from '@tanstack/vue-query'
+import CreateAccountView from '@/components/ui/auth/CreateAccount.vue'
import SignUpView from '@/components/ui/auth/SignUp.vue'
const client = injectModrinthClient()
@@ -35,6 +43,14 @@ const messages = defineMessages({
id: 'auth.sign-up.title',
defaultMessage: 'Sign Up',
},
+ ageRequirementWarningTitle: {
+ id: 'auth.sign-up.age-requirement.warning-title',
+ defaultMessage: 'Age requirement',
+ },
+ under13HelperText: {
+ id: 'auth.create-account.date-of-birth.under13-helper',
+ defaultMessage: 'You cannot create an account at Modrinth unless you are 13 years old.',
+ },
})
useHead({
@@ -46,6 +62,7 @@ const route = useNativeRoute()
const redirectTarget = route.query.redirect
const showOtherOptions = ref(false)
+const isCreateAccountStep = ref(false)
if (auth.value.user) {
await navigateTo('/dashboard')
@@ -73,12 +90,38 @@ const { data: globals } = useQuery({
const email = ref('')
const password = ref('')
+const dateOfBirth = ref('')
+const username = ref('')
const token = ref('')
const subscribe = ref(false)
+async function continueWithEmail() {
+ startLoading()
+ try {
+ const generatedUsername = generateUsernameFromEmail(email.value)
+
+ await client.labrinth.auth_v2.validateCreateAccount({
+ username: generatedUsername,
+ password: password.value,
+ email: email.value,
+ })
+
+ token.value = ''
+ username.value = generatedUsername
+ isCreateAccountStep.value = true
+ } catch (err) {
+ addNotification({
+ title: formatMessage(commonMessages.errorNotificationTitle),
+ text: err.data ? err.data.description : err,
+ type: 'error',
+ })
+ }
+ stopLoading()
+}
+
function generateUsernameFromEmail(emailAddress) {
- const [localPart = '', domainPart = ''] = emailAddress.trim().toLowerCase().split('@')
- const sanitized = `${localPart}_${domainPart}`
+ const [localPart = ''] = emailAddress.trim().toLowerCase().split('@')
+ const sanitized = localPart
.replace(/[^a-zA-Z0-9_-]/g, '_')
.replace(/_+/g, '_')
.replace(/^_+|_+$/g, '')
@@ -90,7 +133,7 @@ async function createAccount() {
startLoading()
try {
const res = await client.labrinth.auth_v2.createAccount({
- username: generateUsernameFromEmail(email.value),
+ username: username.value.trim() || generateUsernameFromEmail(email.value),
password: password.value,
email: email.value,
challenge: token.value,
diff --git a/packages/api-client/src/modules/labrinth/auth/v2.ts b/packages/api-client/src/modules/labrinth/auth/v2.ts
index 53c9b2669e..e1829d7726 100644
--- a/packages/api-client/src/modules/labrinth/auth/v2.ts
+++ b/packages/api-client/src/modules/labrinth/auth/v2.ts
@@ -57,6 +57,22 @@ export class LabrinthAuthV2Module extends AbstractModule {
})
}
+ /**
+ * Validate email/password inputs for account creation without creating an account.
+ *
+ * @param data - Prospective account credentials
+ */
+ public async validateCreateAccount(
+ data: Labrinth.Auth.v2.ValidateCreateAccountRequest,
+ ): Promise {
+ return this.client.request(`/auth/create/validate`, {
+ api: 'labrinth',
+ version: 2,
+ method: 'POST',
+ body: data,
+ })
+ }
+
/**
* Create a new account from an OAuth callback flow state
*
diff --git a/packages/api-client/src/modules/labrinth/types.ts b/packages/api-client/src/modules/labrinth/types.ts
index 1e03777162..78b84b0cac 100644
--- a/packages/api-client/src/modules/labrinth/types.ts
+++ b/packages/api-client/src/modules/labrinth/types.ts
@@ -278,6 +278,12 @@ export namespace Labrinth {
session: string
}
+ export type ValidateCreateAccountRequest = {
+ username: string
+ password: string
+ email: string
+ }
+
export type CreateOAuthAccountRequest = {
username: string
state: string