Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions examples/nextjs/lib/firebase/clientApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { initializeApp, getApps } from "firebase/app";
import { firebaseConfig } from "./config";
import { connectAuthEmulator, getAuth } from "firebase/auth";
import { autoAnonymousLogin, initializeUI } from "@firebase-ui/core";
import { customLanguage, english } from "@firebase-ui/translations";

export const firebaseApp = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];

Expand All @@ -29,19 +28,6 @@ export const auth = getAuth(firebaseApp);
export const ui = initializeUI({
app: firebaseApp,
behaviors: [autoAnonymousLogin()],
translations: [
customLanguage(english.locale, {
labels: {
signIn: "Sign In",
},
prompts: {
signInToAccount: "Sign in to your account",
},
errors: {
invalidEmail: "Please enter a valid email address",
},
}),
],
});

connectAuthEmulator(auth, "http://localhost:9099");
14 changes: 0 additions & 14 deletions examples/react/lib/firebase/clientApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { initializeApp, getApps } from "firebase/app";
import { firebaseConfig } from "./config";
import { connectAuthEmulator, getAuth } from "firebase/auth";
import { autoAnonymousLogin, initializeUI } from "@firebase-ui/core";
import { customLanguage, english } from "@firebase-ui/translations";

export const firebaseApp = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];

Expand All @@ -29,19 +28,6 @@ export const auth = getAuth(firebaseApp);
export const ui = initializeUI({
app: firebaseApp,
behaviors: [autoAnonymousLogin()],
translations: [
customLanguage(english.locale, {
labels: {
signIn: "Sign In",
},
prompts: {
signInToAccount: "Sign in to your account",
},
errors: {
invalidEmail: "Please enter a valid email address",
},
}),
],
});

if (import.meta.env.MODE === "development") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
FirebaseUIError,
completeEmailLinkSignIn,
sendSignInLinkToEmail,
FirebaseUIConfiguration,
} from "@firebase-ui/core";
import { firstValueFrom } from "rxjs";

Expand Down Expand Up @@ -74,7 +75,7 @@ export class EmailLinkFormComponent implements OnInit {
formError: string | null = null;
emailSent = false;
private formSchema: any;
private config: any;
private config: FirebaseUIConfiguration;

form = injectForm({
defaultValues: {
Expand All @@ -86,7 +87,7 @@ export class EmailLinkFormComponent implements OnInit {
try {
this.config = await firstValueFrom(this.ui.config());

this.formSchema = createEmailLinkFormSchema(this.config?.translations);
this.formSchema = createEmailLinkFormSchema(this.config);

this.form.update({
validators: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { injectForm, TanStackField } from "@tanstack/angular-form";
import { FirebaseUI } from "../../../provider";
import { ButtonComponent } from "../../../components/button/button.component";
import { TermsAndPrivacyComponent } from "../../../components/terms-and-privacy/terms-and-privacy.component";
import { createEmailFormSchema, EmailFormSchema, FirebaseUIError, signInWithEmailAndPassword } from "@firebase-ui/core";
import { createEmailFormSchema, EmailFormSchema, FirebaseUIConfiguration, FirebaseUIError, signInWithEmailAndPassword } from "@firebase-ui/core";
import { firstValueFrom } from "rxjs";
import { Router } from "@angular/router";

Expand Down Expand Up @@ -105,7 +105,7 @@ export class EmailPasswordFormComponent implements OnInit {

formError: string | null = null;
private formSchema: any;
private config: any;
private config: FirebaseUIConfiguration;

form = injectForm({
defaultValues: {
Expand All @@ -120,7 +120,7 @@ export class EmailPasswordFormComponent implements OnInit {
this.config = await firstValueFrom(this.ui.config());

// Create schema once
this.formSchema = createEmailFormSchema(this.config?.translations);
this.formSchema = createEmailFormSchema(this.config);

// Apply schema to form validators
this.form.update({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { FirebaseUI } from "../../../provider";
import { Auth } from "@angular/fire/auth";
import { ButtonComponent } from "../../../components/button/button.component";
import { TermsAndPrivacyComponent } from "../../../components/terms-and-privacy/terms-and-privacy.component";
import { createForgotPasswordFormSchema, FirebaseUIError, sendPasswordResetEmail } from "@firebase-ui/core";
import { createForgotPasswordFormSchema, FirebaseUIConfiguration, FirebaseUIError, sendPasswordResetEmail } from "@firebase-ui/core";
import { firstValueFrom } from "rxjs";
import { Router } from "@angular/router";

Expand Down Expand Up @@ -80,7 +80,7 @@ export class ForgotPasswordFormComponent implements OnInit {
formError: string | null = null;
emailSent = false;
private formSchema: any;
private config: any;
private config: FirebaseUIConfiguration;

form = injectForm({
defaultValues: {
Expand All @@ -92,7 +92,7 @@ export class ForgotPasswordFormComponent implements OnInit {
try {
this.config = await firstValueFrom(this.ui.config());

this.formSchema = createForgotPasswordFormSchema(this.config?.translations);
this.formSchema = createForgotPasswordFormSchema(this.config);

this.form.update({
validators: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
formatPhoneNumberWithCountry,
confirmPhoneNumber,
signInWithPhoneNumber,
FirebaseUIConfiguration,
} from "@firebase-ui/core";
import { interval, Subscription, firstValueFrom } from "rxjs";
import { Router } from "@angular/router";
Expand Down Expand Up @@ -102,7 +103,7 @@ export class PhoneNumberFormComponent implements OnInit, OnDestroy {
recaptchaVerifier: RecaptchaVerifier | null = null;
selectedCountry: CountryData = countryData[0];
private formSchema: any;
private config: any;
private config: FirebaseUIConfiguration;

form = injectForm({
defaultValues: {
Expand All @@ -114,7 +115,7 @@ export class PhoneNumberFormComponent implements OnInit, OnDestroy {
try {
this.config = await firstValueFrom(this.ui.config());

this.formSchema = createPhoneFormSchema(this.config?.translations).pick({
this.formSchema = createPhoneFormSchema(this.config).pick({
phoneNumber: true,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
EmailFormSchema,
FirebaseUIError,
createUserWithEmailAndPassword,
FirebaseUIConfiguration,
} from "@firebase-ui/core";
import { Auth } from "@angular/fire/auth";
import { TermsAndPrivacyComponent } from "../../../components/terms-and-privacy/terms-and-privacy.component";
Expand Down Expand Up @@ -105,7 +106,7 @@ export class RegisterFormComponent implements OnInit {

formError: string | null = null;
private formSchema: any;
private config: any;
private config: FirebaseUIConfiguration;

form = injectForm({
defaultValues: {
Expand All @@ -118,7 +119,7 @@ export class RegisterFormComponent implements OnInit {
try {
this.config = await firstValueFrom(this.ui.config());

this.formSchema = createEmailFormSchema(this.config?.translations);
this.formSchema = createEmailFormSchema(this.config);

this.form.update({
validators: {
Expand Down
7 changes: 6 additions & 1 deletion packages/angular/tsconfig.lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"types": []
"types": [],
"baseUrl": ".",
"paths": {
"@firebase-ui/core": ["../core/src/index.ts"],
"@firebase-ui/translations": ["../translations/src/index.ts"]
}
},
"exclude": ["**/*.spec.ts"]
}
31 changes: 8 additions & 23 deletions packages/core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import { english, Locale, RegisteredTranslations, TranslationsConfig } from "@firebase-ui/translations";
import { enUs, RegisteredLocale } from "@firebase-ui/translations";
import type { FirebaseApp } from "firebase/app";
import { Auth, getAuth } from "firebase/auth";
import { deepMap, DeepMapStore, map } from "nanostores";
Expand All @@ -23,20 +23,18 @@ import { FirebaseUIState } from "./state";

type FirebaseUIConfigurationOptions = {
app: FirebaseApp;
locale?: Locale | undefined;
translations?: RegisteredTranslations[] | undefined;
behaviors?: Partial<Behavior<keyof BehaviorHandlers>>[] | undefined;
recaptchaMode?: "normal" | "invisible" | undefined;
locale?: RegisteredLocale;
behaviors?: Partial<Behavior<keyof BehaviorHandlers>>[];
recaptchaMode?: "normal" | "invisible";
};

export type FirebaseUIConfiguration = {
app: FirebaseApp;
getAuth: () => Auth;
setLocale: (locale: Locale) => void;
setLocale: (locale: RegisteredLocale) => void;
state: FirebaseUIState;
setState: (state: FirebaseUIState) => void;
locale: Locale;
translations: TranslationsConfig;
locale: RegisteredLocale;
behaviors: Partial<Record<BehaviorKey, BehaviorHandlers[BehaviorKey]>>;
recaptchaMode: "normal" | "invisible";
};
Expand All @@ -57,25 +55,13 @@ export function initializeUI(config: FirebaseUIConfigurationOptions, name: strin
{} as Record<BehaviorKey, BehaviorHandlers[BehaviorKey]>
);

config.translations ??= [];

// TODO: Is this right?
config.translations.push(english);

const translations = config.translations?.reduce((acc, translation) => {
return {
...acc,
[translation.locale]: translation.translations,
};
}, {} as TranslationsConfig);

$config.setKey(
name,
deepMap<FirebaseUIConfiguration>({
app: config.app,
getAuth: () => getAuth(config.app),
locale: config.locale ?? english.locale,
setLocale: (locale: Locale) => {
locale: config.locale ?? enUs,
setLocale: (locale: RegisteredLocale) => {
const current = $config.get()[name]!;
current.setKey(`locale`, locale);
},
Expand All @@ -84,7 +70,6 @@ export function initializeUI(config: FirebaseUIConfigurationOptions, name: strin
const current = $config.get()[name]!;
current.setKey(`state`, state);
},
translations,
behaviors: behaviors ?? {},
recaptchaMode: config.recaptchaMode ?? "normal",
})
Expand Down
22 changes: 7 additions & 15 deletions packages/core/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,16 @@
* limitations under the License.
*/

import {
english,
ERROR_CODE_MAP,
ErrorCode,
getTranslation,
Locale,
TranslationsConfig,
} from "@firebase-ui/translations";
import { ERROR_CODE_MAP, ErrorCode } from "@firebase-ui/translations";
import { getTranslation } from "./translations";
import { FirebaseUIConfiguration } from "./config";
export class FirebaseUIError extends Error {
code: string;

constructor(error: any, translations?: TranslationsConfig, locale?: Locale) {
constructor(error: any, ui: FirebaseUIConfiguration) {
const errorCode: ErrorCode = error?.customData?.message?.match?.(/\(([^)]+)\)/)?.at(1) || error?.code || "unknown";
const translationKey = ERROR_CODE_MAP[errorCode] || "unknownError";
const message = getTranslation("errors", translationKey, translations, locale ?? english.locale);
const message = getTranslation(ui, "errors", translationKey);

super(message);
this.name = "FirebaseUIError";
Expand All @@ -44,7 +38,6 @@ export function handleFirebaseError(
enableHandleExistingCredential?: boolean;
}
): never {
const { translations, locale: defaultLocale } = ui;
if (error?.code === "auth/account-exists-with-different-credential") {
if (opts?.enableHandleExistingCredential && error.credential) {
window.sessionStorage.setItem("pendingCred", JSON.stringify(error.credential));
Expand All @@ -59,14 +52,13 @@ export function handleFirebaseError(
email: error.customData?.email,
},
},
translations,
defaultLocale
ui,
);
}

// TODO: Debug why instanceof FirebaseError is not working
if (error?.name === "FirebaseError") {
throw new FirebaseUIError(error, translations, defaultLocale);
throw new FirebaseUIError(error, ui);
}
throw new FirebaseUIError({ code: "unknown" }, translations, defaultLocale);
throw new FirebaseUIError({ code: "unknown" }, ui);
}
25 changes: 13 additions & 12 deletions packages/core/src/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,40 @@

import { z } from "zod";
import { RecaptchaVerifier } from "firebase/auth";
import { type TranslationsConfig, getTranslation } from "@firebase-ui/translations";
import { getTranslation } from "./translations";
import { FirebaseUIConfiguration } from "./config";

export const LoginTypes = ["email", "phone", "anonymous", "emailLink", "google"] as const;
export type LoginType = (typeof LoginTypes)[number];
export type AuthMode = "signIn" | "signUp";

export function createEmailFormSchema(translations?: TranslationsConfig) {
export function createEmailFormSchema(ui: FirebaseUIConfiguration) {
return z.object({
email: z.string().email({ message: getTranslation("errors", "invalidEmail", translations) }),
password: z.string().min(8, { message: getTranslation("errors", "weakPassword", translations) }),
email: z.string().email({ message: getTranslation(ui, "errors", "invalidEmail") }),
password: z.string().min(8, { message: getTranslation(ui, "errors", "weakPassword") }),
});
}

export function createForgotPasswordFormSchema(translations?: TranslationsConfig) {
export function createForgotPasswordFormSchema(ui: FirebaseUIConfiguration) {
return z.object({
email: z.string().email({ message: getTranslation("errors", "invalidEmail", translations) }),
email: z.string().email({ message: getTranslation(ui, "errors", "invalidEmail") }),
});
}

export function createEmailLinkFormSchema(translations?: TranslationsConfig) {
export function createEmailLinkFormSchema(ui: FirebaseUIConfiguration) {
return z.object({
email: z.string().email({ message: getTranslation("errors", "invalidEmail", translations) }),
email: z.string().email({ message: getTranslation(ui, "errors", "invalidEmail") }),
});
}

export function createPhoneFormSchema(translations?: TranslationsConfig) {
export function createPhoneFormSchema(ui: FirebaseUIConfiguration) {
return z.object({
phoneNumber: z
.string()
.min(1, { message: getTranslation("errors", "missingPhoneNumber", translations) })
.min(10, { message: getTranslation("errors", "invalidPhoneNumber", translations) }),
.min(1, { message: getTranslation(ui, "errors", "missingPhoneNumber") })
.min(10, { message: getTranslation(ui, "errors", "invalidPhoneNumber") }),
verificationCode: z.string().refine((val) => !val || val.length >= 6, {
message: getTranslation("errors", "invalidVerificationCode", translations),
message: getTranslation(ui, "errors", "invalidVerificationCode"),
}),
recaptchaVerifier: z.instanceof(RecaptchaVerifier),
});
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ export function getTranslation<T extends TranslationCategory>(
category: T,
key: TranslationKey<T>
) {
return _getTranslation(category, key, ui.translations, ui.locale);
return _getTranslation(ui.locale, category, key);
}
Loading
Loading