Skip to content

Commit 3bca15d

Browse files
committed
chore(*): resolved conflicts
2 parents a1585ff + 3485eed commit 3bca15d

File tree

24 files changed

+1404
-120
lines changed

24 files changed

+1404
-120
lines changed

README.md

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -202,12 +202,11 @@ The initializeUI function accepts an options object that allows you to customize
202202
### Type Definition
203203

204204
```js
205-
type FirebaseUIConfigurationOptions = {
205+
type FirebaseUIOptions = {
206206
app: FirebaseApp;
207-
locale?: Locale | undefined;
208-
translations?: RegisteredTranslations[] | undefined;
209-
behaviors?: Partial<Behavior<keyof BehaviorHandlers>>[] | undefined;
210-
recaptchaMode?: 'normal' | 'invisible' | undefined;
207+
auth?: Auth;
208+
locale?: Locale;
209+
behaviors?: Behavior<any>[];
211210
};
212211
```
213212

@@ -290,7 +289,7 @@ const ui = initializeUI({
290289
Configuration Type:
291290

292291
```js
293-
type FirebaseUIConfigurationOptions = {
292+
type FirebaseUIOptions = {
294293
app: FirebaseApp;
295294
locale?: Locale | undefined;
296295
translations?: RegisteredTranslations[] | undefined;
@@ -303,61 +302,61 @@ type FirebaseUIConfigurationOptions = {
303302

304303
**signInWithEmailAndPassword**: Signs in the user based on an email/password credential.
305304

306-
- _ui_: FirebaseUIConfiguration
305+
- _ui_: FirebaseUI
307306
- _email_: string
308307
- _password_: string
309308

310309
**createUserWithEmailAndPassword**: Creates a user account based on an email/password credential.
311310

312-
- _ui_: FirebaseUIConfiguration
311+
- _ui_: FirebaseUI
313312
- _email_: string
314313
- _password_: string
315314

316315
**signInWithPhoneNumber**: Signs in the user based on a provided phone number, using ReCaptcha to verify the sign-in.
317316

318-
- _ui_: FirebaseUIConfiguration
317+
- _ui_: FirebaseUI
319318
- _phoneNumber_: string
320319
- _recaptchaVerifier_: string
321320

322321
**confirmPhoneNumber**: Verifies the phonenumber credential and signs in the user.
323322

324-
- _ui_: FirebaseUIConfiguration
323+
- _ui_: FirebaseUI
325324
- _confirmationResult_: [ConfirmationResult](https://firebase.google.com/docs/reference/node/firebase.auth.ConfirmationResult)
326325
- _verificationCode_: string
327326

328327
**sendPasswordResetEmail**: Sends password reset instructions to an email account.
329328

330-
- _ui_: FirebaseUIConfiguration
329+
- _ui_: FirebaseUI
331330
- _email_: string
332331

333332
**sendSignInLinkToEmail**: Send an sign-in links to an email account.
334333

335-
- _ui_: FirebaseUIConfiguration
334+
- _ui_: FirebaseUI
336335
- _email_: string
337336

338337
**signInWithEmailLink**: Signs in with the user with the email link. If `autoUpgradeAnonymousCredential` then a pending credential will be handled.
339338

340-
- _ui_: FirebaseUIConfiguration
339+
- _ui_: FirebaseUI
341340
- _email_: string
342341
- _link_: string
343342

344343
**signInAnonymously**: Signs in as an anonymous user.
345344

346-
- _ui_: FirebaseUIConfiguration
345+
- _ui_: FirebaseUI
347346

348347
**signInWithOAuth**: Signs in with a provider such as Google via a redirect link. If `autoUpgradeAnonymousCredential` then the account will upgraded.
349348

350-
- _ui_: FirebaseUIConfiguration
349+
- _ui_: FirebaseUI
351350
- _provider_: [AuthProvider](https://firebase.google.com/docs/reference/node/firebase.auth.AuthProvider)
352351

353352
**completeEmailLinkSignIn**: Completes the signing process based on a user signing in with an email link.
354353

355-
- _ui_: FirebaseUIConfiguration
354+
- _ui_: FirebaseUI
356355
- _currentUrl_: string
357356

358357
#### Provide a Store via Context
359358

360-
Using the returned `FirebaseUIConfiguration`, it is reccomended to use local context/providers/dependency-injection to expose the FirebaseUIConfiguration to the application. Here is an example context wrapper which accepts the configuration as a `ui` parameter:
359+
Using the returned `FirebaseUI`, it is reccomended to use local context/providers/dependency-injection to expose the FirebaseUI to the application. Here is an example context wrapper which accepts the configuration as a `ui` parameter:
361360

362361
```js
363362
/** Creates a framework-agnostic context for Firebase UI configuration **/
@@ -391,7 +390,7 @@ export function createFirebaseUIContext(initialConfig) {
391390
FirebaseUI Configuration Type:
392391

393392
```js
394-
export type FirebaseUIConfiguration = {
393+
export type FirebaseUI = {
395394
app: FirebaseApp,
396395
getAuth: () => Auth,
397396
setLocale: (locale: Locale) => void,
@@ -556,7 +555,7 @@ The core library provides a function for handling errors.
556555

557556
```js
558557
export function handleFirebaseError(
559-
ui: FirebaseUIConfiguration,
558+
ui: FirebaseUI,
560559
error: any,
561560
opts?: {
562561
enableHandleExistingCredential?: boolean;
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/**
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { Component, inject, Input, OnInit } from "@angular/core";
18+
import { CommonModule } from "@angular/common";
19+
import { injectForm, TanStackField } from "@tanstack/angular-form";
20+
import { FirebaseUI } from "../../../provider";
21+
import { ButtonComponent } from "../../../components/button/button.component";
22+
import { TermsAndPrivacyComponent } from "../../../components/terms-and-privacy/terms-and-privacy.component";
23+
import {
24+
createEmailLinkFormSchema,
25+
FirebaseUIError,
26+
completeEmailLinkSignIn,
27+
sendSignInLinkToEmail,
28+
FirebaseUI,
29+
} from "@firebase-ui/core";
30+
import { firstValueFrom } from "rxjs";
31+
32+
@Component({
33+
selector: "fui-email-link-form",
34+
standalone: true,
35+
imports: [CommonModule, TanStackField, ButtonComponent, TermsAndPrivacyComponent],
36+
template: `
37+
<div *ngIf="emailSent" class="fui-form">
38+
{{ emailSentMessage | async }}
39+
</div>
40+
<form *ngIf="!emailSent" (submit)="handleSubmit($event)" class="fui-form">
41+
<fieldset>
42+
<ng-container [tanstackField]="form" name="email" #email="field">
43+
<label [for]="email.api.name">
44+
<span>{{ emailLabel | async }}</span>
45+
<input
46+
type="email"
47+
[id]="email.api.name"
48+
[name]="email.api.name"
49+
[value]="email.api.state.value"
50+
(blur)="email.api.handleBlur()"
51+
(input)="email.api.handleChange($any($event).target.value)"
52+
[attr.aria-invalid]="!!email.api.state.meta.errors.length"
53+
/>
54+
<span role="alert" aria-live="polite" class="fui-form__error" *ngIf="!!email.api.state.meta.errors.length">
55+
{{ email.api.state.meta.errors.join(", ") }}
56+
</span>
57+
</label>
58+
</ng-container>
59+
</fieldset>
60+
61+
<fui-terms-and-privacy></fui-terms-and-privacy>
62+
63+
<fieldset>
64+
<fui-button type="submit">
65+
{{ sendSignInLinkLabel | async }}
66+
</fui-button>
67+
<div class="fui-form__error" *ngIf="formError">{{ formError }}</div>
68+
</fieldset>
69+
</form>
70+
`,
71+
})
72+
export class EmailLinkFormComponent implements OnInit {
73+
private ui = inject(FirebaseUI);
74+
75+
formError: string | null = null;
76+
emailSent = false;
77+
private formSchema: any;
78+
private config: FirebaseUI;
79+
80+
form = injectForm({
81+
defaultValues: {
82+
email: "",
83+
},
84+
});
85+
86+
async ngOnInit() {
87+
try {
88+
this.config = await firstValueFrom(this.ui.config());
89+
90+
this.formSchema = createEmailLinkFormSchema(this.config);
91+
92+
this.form.update({
93+
validators: {
94+
onSubmit: this.formSchema,
95+
onBlur: this.formSchema,
96+
},
97+
});
98+
99+
this.completeSignIn();
100+
} catch (error) {
101+
this.formError = await firstValueFrom(this.ui.translation("errors", "unknownError"));
102+
}
103+
}
104+
105+
private async completeSignIn() {
106+
try {
107+
await completeEmailLinkSignIn(await firstValueFrom(this.ui.config()), window.location.href);
108+
} catch (error) {
109+
if (error instanceof FirebaseUIError) {
110+
this.formError = error.message;
111+
}
112+
}
113+
}
114+
115+
async handleSubmit(event: SubmitEvent) {
116+
event.preventDefault();
117+
event.stopPropagation();
118+
119+
const email = this.form.state.values.email;
120+
121+
if (!email) {
122+
return;
123+
}
124+
125+
await this.sendSignInLink(email);
126+
}
127+
128+
async sendSignInLink(email: string) {
129+
this.formError = null;
130+
131+
try {
132+
const validationResult = this.formSchema.safeParse({
133+
email,
134+
});
135+
136+
if (!validationResult.success) {
137+
const validationErrors = validationResult.error.format();
138+
139+
if (validationErrors.email?._errors?.length) {
140+
this.formError = validationErrors.email._errors[0];
141+
return;
142+
}
143+
144+
this.formError = await firstValueFrom(this.ui.translation("errors", "unknownError"));
145+
return;
146+
}
147+
148+
await sendSignInLinkToEmail(await firstValueFrom(this.ui.config()), email);
149+
150+
this.emailSent = true;
151+
} catch (error) {
152+
if (error instanceof FirebaseUIError) {
153+
this.formError = error.message;
154+
return;
155+
}
156+
157+
this.formError = await firstValueFrom(this.ui.translation("errors", "unknownError"));
158+
}
159+
}
160+
161+
get emailLabel() {
162+
return this.ui.translation("labels", "emailAddress");
163+
}
164+
165+
get sendSignInLinkLabel() {
166+
return this.ui.translation("labels", "sendSignInLink");
167+
}
168+
169+
get emailSentMessage() {
170+
return this.ui.translation("messages", "signInLinkSent");
171+
}
172+
}

0 commit comments

Comments
 (0)