From cea77c417c56551cb05d1d5246ba631da78c8bf6 Mon Sep 17 00:00:00 2001 From: Giddh's Black Tiger Date: Wed, 15 Apr 2026 18:13:11 +0530 Subject: [PATCH 01/16] refactor: add registration flow with email verification and onboarding page - Add registration NgRx state, actions, effects, and reducer to handle user sign-up - Create onboarding component to handle email verification code exchange and auto-login - Add /app/onboarding route with verification code processing and error handling - Update app component to exclude onboarding route from dashboard redirect logic - Consolidate website route checks into array and add /register to website routes list - Replace --- apps/36-blocks/src/app/app.component.ts | 19 +- apps/36-blocks/src/app/app.config.ts | 5 +- .../onboarding/onboarding.component.html | 52 +++ .../onboarding/onboarding.component.scss | 3 + .../panel/onboarding/onboarding.component.ts | 127 +++++++ apps/36-blocks/src/app/panel/panel.routes.ts | 4 + .../app/website/about/about.component.html | 22 +- .../website/contact/contact.component.html | 20 -- .../src/app/website/home/home.component.html | 2 +- .../src/app/website/home/home.component.scss | 63 ---- .../home/ngrx/actions/registration.action.ts | 32 ++ .../home/ngrx/effects/registration.effects.ts | 42 +++ .../ngrx/reducers/registration.reducer.ts | 46 +++ .../ngrx/selector/registration.selector.ts | 24 ++ .../layout/website-layout.component.html | 16 + .../website/pricing/pricing.component.html | 10 +- .../app/website/pricing/pricing.component.ts | 3 +- .../website/privacy/privacy.component.html | 20 -- .../register/register-page.component.html | 338 ++++++++++++++++++ .../register/register-page.component.scss | 3 + .../register/register-page.component.ts | 134 +++++++ .../website/security/security.component.html | 20 -- .../app/website/terms/terms.component.html | 20 -- .../src/app/website/website.routes.ts | 4 + .../src/lib/services-proxy-users.module.ts | 4 + libs/urls/users-urls/src/index.ts | 1 + 26 files changed, 852 insertions(+), 182 deletions(-) create mode 100644 apps/36-blocks/src/app/panel/onboarding/onboarding.component.html create mode 100644 apps/36-blocks/src/app/panel/onboarding/onboarding.component.scss create mode 100644 apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts create mode 100644 apps/36-blocks/src/app/website/home/ngrx/actions/registration.action.ts create mode 100644 apps/36-blocks/src/app/website/home/ngrx/effects/registration.effects.ts create mode 100644 apps/36-blocks/src/app/website/home/ngrx/reducers/registration.reducer.ts create mode 100644 apps/36-blocks/src/app/website/home/ngrx/selector/registration.selector.ts create mode 100644 apps/36-blocks/src/app/website/register/register-page.component.html create mode 100644 apps/36-blocks/src/app/website/register/register-page.component.scss create mode 100644 apps/36-blocks/src/app/website/register/register-page.component.ts diff --git a/apps/36-blocks/src/app/app.component.ts b/apps/36-blocks/src/app/app.component.ts index c59fa7b3..a5fd3360 100644 --- a/apps/36-blocks/src/app/app.component.ts +++ b/apps/36-blocks/src/app/app.component.ts @@ -118,16 +118,21 @@ export class AppComponent extends BaseComponent implements OnInit, OnDestroy { if (isPlatformBrowser(this.platformId)) { this.actions$.pipe(ofType(logInActions.authenticatedAction), takeUntil(this.destroy$)).subscribe(() => { const currentUrl = this.router.url; + const websiteRoutes = [ + '/pricing', + '/about', + '/contact', + '/security', + '/privacy', + '/terms', + '/register', + ]; const isOnWebsiteRoute = currentUrl === '/' || currentUrl === '' || - currentUrl.startsWith('/pricing') || - currentUrl.startsWith('/about') || - currentUrl.startsWith('/contact') || - currentUrl.startsWith('/security') || - currentUrl.startsWith('/privacy') || - currentUrl.startsWith('/terms'); - if (isOnWebsiteRoute) { + websiteRoutes.some((route) => currentUrl.startsWith(route)); + const isOnboardingRoute = currentUrl.startsWith('/app/onboarding'); + if (isOnWebsiteRoute && !isOnboardingRoute) { this.router.navigate(['/app/dashboard']); } }); diff --git a/apps/36-blocks/src/app/app.config.ts b/apps/36-blocks/src/app/app.config.ts index 8a254d25..7960b13b 100644 --- a/apps/36-blocks/src/app/app.config.ts +++ b/apps/36-blocks/src/app/app.config.ts @@ -15,8 +15,10 @@ import { appRoutes } from './app.routes'; import { environment } from '../environments/environment'; import { reducers, clearStateMetaReducer } from './core/ngrx/store/app.state'; import { loginsReducer } from './website/home/ngrx/store/login.state'; +import { registrationReducer } from './website/home/ngrx/reducers/registration.reducer'; import { RootEffects } from './core/ngrx/effects/root'; import { LogInEffects } from './website/home/ngrx/effects/login.effects'; +import { RegistrationEffects } from './website/home/ngrx/effects/registration.effects'; import { ErrorInterceptor } from '@proxy/services/interceptor/errorInterceptor'; import { ProxyBaseUrls } from '@proxy/models/root-models'; import { AuthInitializerService } from './core/auth-initializer.service'; @@ -33,7 +35,8 @@ export const appConfig: ApplicationConfig = { provideHttpClient(withFetch(), withInterceptorsFromDi()), provideStore(reducers, { metaReducers: [clearStateMetaReducer] }), provideState('auth', loginsReducer), - provideEffects([RootEffects, LogInEffects]), + provideState('registration', registrationReducer), + provideEffects([RootEffects, LogInEffects, RegistrationEffects]), ...(!environment.production ? [provideStoreDevtools({ maxAge: 25, serialize: true })] : []), { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }, { diff --git a/apps/36-blocks/src/app/panel/onboarding/onboarding.component.html b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.html new file mode 100644 index 00000000..00cc75b1 --- /dev/null +++ b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.html @@ -0,0 +1,52 @@ +
+ @if (onboardingError()) { + + + } @else { + +
+ +

Verifying your account

+

Please wait while we complete your sign-up…

+
+ } +
diff --git a/apps/36-blocks/src/app/panel/onboarding/onboarding.component.scss b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.scss new file mode 100644 index 00000000..7f26ddcb --- /dev/null +++ b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.scss @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts new file mode 100644 index 00000000..6f873c1c --- /dev/null +++ b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts @@ -0,0 +1,127 @@ +import { + ChangeDetectionStrategy, + Component, + inject, + NgZone, + OnDestroy, + OnInit, + PLATFORM_ID, + signal, +} from '@angular/core'; +import { isPlatformBrowser } from '@angular/common'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Actions, ofType } from '@ngrx/effects'; +import { Store } from '@ngrx/store'; +import { Subject } from 'rxjs'; +import { take, takeUntil } from 'rxjs/operators'; +import { AuthService } from '@proxy/services/proxy/auth'; +import { UsersService } from '@proxy/services/proxy/users'; +import * as logInActions from '../../website/home/ngrx/actions/login.action'; + +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'proxy-onboarding', + imports: [], + templateUrl: './onboarding.component.html', + styleUrl: './onboarding.component.scss', +}) +export class OnboardingComponent implements OnInit, OnDestroy { + private readonly activatedRoute = inject(ActivatedRoute); + private readonly router = inject(Router); + private readonly authService = inject(AuthService); + private readonly usersService = inject(UsersService); + private readonly store = inject(Store); + private readonly actions$ = inject(Actions); + private readonly platformId = inject(PLATFORM_ID); + private readonly ngZone = inject(NgZone); + private readonly destroy$ = new Subject(); + + public readonly onboardingError = signal(null); + public readonly onboardingInProgress = signal(true); + public readonly redirectCountdown = signal(3); + + private redirectTimer: ReturnType | null = null; + + public ngOnInit(): void { + if (!isPlatformBrowser(this.platformId)) { + return; + } + + const verificationCode = this.activatedRoute.snapshot.queryParamMap.get('code'); + + if (!verificationCode) { + this.onboardingError.set('No verification code found. Please check your email link and try again.'); + this.onboardingInProgress.set(false); + this.redirectToHomeAfterDelay(); + return; + } + + this.usersService + .exchangeToken(verificationCode) + .pipe(take(1), takeUntil(this.destroy$)) + .subscribe({ + next: (response) => { + const jwtToken = response?.token; + if (!jwtToken) { + this.onboardingError.set('Verification failed: invalid server response. Please try again.'); + this.onboardingInProgress.set(false); + this.redirectToHomeAfterDelay(); + return; + } + + this.authService.setTokenSync(jwtToken); + + this.actions$ + .pipe(ofType(logInActions.authenticatedAction), take(1), takeUntil(this.destroy$)) + .subscribe(() => { + this.router.navigate(['/app/features/create']); + }); + + this.actions$ + .pipe(ofType(logInActions.logInActionError), take(1), takeUntil(this.destroy$)) + .subscribe(({ errors }) => { + this.onboardingError.set(errors?.join(' ') || 'Verification failed. Please try again.'); + this.onboardingInProgress.set(false); + }); + + this.store.dispatch(logInActions.getUserAction()); + }, + error: (error) => { + const errorBody = error?.error; + const resolvedMessage = + errorBody?.errors?.message || + errorBody?.data?.message || + errorBody?.message || + 'Verification failed. Please try again.'; + this.onboardingError.set(resolvedMessage); + this.onboardingInProgress.set(false); + this.redirectToHomeAfterDelay(); + }, + }); + } + + private redirectToHomeAfterDelay(): void { + this.redirectCountdown.set(3); + this.redirectTimer = this.ngZone.run(() => + setInterval(() => { + const remaining = this.redirectCountdown() - 1; + this.redirectCountdown.set(remaining); + if (remaining <= 0) { + if (this.redirectTimer) { + clearInterval(this.redirectTimer); + this.redirectTimer = null; + } + this.router.navigate(['/']); + } + }, 1000) + ); + } + + public ngOnDestroy(): void { + if (this.redirectTimer) { + clearInterval(this.redirectTimer); + } + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/apps/36-blocks/src/app/panel/panel.routes.ts b/apps/36-blocks/src/app/panel/panel.routes.ts index 7541981e..a8d69618 100644 --- a/apps/36-blocks/src/app/panel/panel.routes.ts +++ b/apps/36-blocks/src/app/panel/panel.routes.ts @@ -6,6 +6,10 @@ import { ProjectGuard } from './guard/project.guard'; const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['login']); export const panelRoutes: Route[] = [ + { + path: 'onboarding', + loadComponent: () => import('./onboarding/onboarding.component').then((c) => c.OnboardingComponent), + }, { path: '', loadComponent: () => import('./layout/layout.component').then((c) => c.LayoutComponent), diff --git a/apps/36-blocks/src/app/website/about/about.component.html b/apps/36-blocks/src/app/website/about/about.component.html index d832d251..dd3b1c90 100644 --- a/apps/36-blocks/src/app/website/about/about.component.html +++ b/apps/36-blocks/src/app/website/about/about.component.html @@ -1,26 +1,6 @@
-

Ready to get s

Ship auth in 5 minutes. Free forever on the Starter plan.

Get Started Free diff --git a/apps/36-blocks/src/app/website/contact/contact.component.html b/apps/36-blocks/src/app/website/contact/contact.component.html index c0b15829..b3311f26 100644 --- a/apps/36-blocks/src/app/website/contact/contact.component.html +++ b/apps/36-blocks/src/app/website/contact/contact.component.html @@ -1,26 +1,6 @@
-

{{ card.title }}

diff --git a/apps/36-blocks/src/app/website/pricing/pricing.component.html b/apps/36-blocks/src/app/website/pricing/pricing.component.html index 375ee7c9..388bab65 100644 --- a/apps/36-blocks/src/app/website/pricing/pricing.component.html +++ b/apps/36-blocks/src/app/website/pricing/pricing.component.html @@ -1,13 +1,6 @@
-
- +

Pricing plans

. +

+
+ } @else { + +
+ + @if (registrationErrors().length > 0) { + + } + + +
+ +
+ + + @if (getFieldError('firstName')) { + + } +
+ + +
+ + + @if (getFieldError('lastName')) { + + } +
+
+ + +
+ + + @if (getFieldError('email')) { + + } +
+ + +
+ +
+ + + @if (getFieldError('mobile')) { + + } +
+ + +
+ + + @if (getFieldError('username')) { + + } +
+
+ + +
+ +
+ + +
+ @if (getFieldError('password')) { + + } @else { +

At least 8 characters.

+ } +
+ + +
+ + + @if (getFieldError('organizationName')) { + + } +
+ + + + + +

+ Already have an account? + +

+
+ } +
+

diff --git a/apps/36-blocks/src/app/website/register/register-page.component.scss b/apps/36-blocks/src/app/website/register/register-page.component.scss new file mode 100644 index 00000000..7f26ddcb --- /dev/null +++ b/apps/36-blocks/src/app/website/register/register-page.component.scss @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/apps/36-blocks/src/app/website/register/register-page.component.ts b/apps/36-blocks/src/app/website/register/register-page.component.ts new file mode 100644 index 00000000..64879448 --- /dev/null +++ b/apps/36-blocks/src/app/website/register/register-page.component.ts @@ -0,0 +1,134 @@ +import { ChangeDetectionStrategy, Component, inject, OnDestroy, OnInit } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { toSignal } from '@angular/core/rxjs-interop'; +import * as logInActions from '../home/ngrx/actions/login.action'; +import * as registrationActions from '../home/ngrx/actions/registration.action'; +import { + selectRegistrationInProgress, + selectRegistrationSuccess, + selectRegistrationErrors, + selectRegisteredEmail, +} from '../home/ngrx/selector/registration.selector'; + +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'proxy-register-page', + imports: [ReactiveFormsModule, RouterModule], + templateUrl: './register-page.component.html', + styleUrl: './register-page.component.scss', +}) +export class RegisterPageComponent implements OnInit, OnDestroy { + private readonly store = inject(Store); + + public readonly registrationInProgress = toSignal(this.store.select(selectRegistrationInProgress), { + initialValue: false, + }); + public readonly registrationSuccess = toSignal(this.store.select(selectRegistrationSuccess), { + initialValue: false, + }); + public readonly registrationErrors = toSignal(this.store.select(selectRegistrationErrors), { + initialValue: [] as string[], + }); + public readonly registeredEmail = toSignal(this.store.select(selectRegisteredEmail), { + initialValue: null as string | null, + }); + + public readonly registrationFormGroup = new FormGroup({ + firstName: new FormControl('', { + nonNullable: true, + validators: [Validators.required, Validators.minLength(2)], + }), + lastName: new FormControl('', { + nonNullable: true, + validators: [Validators.required, Validators.minLength(2)], + }), + email: new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.email] }), + mobile: new FormControl('', { + nonNullable: true, + validators: [Validators.required, Validators.pattern(/^\d{10,15}$/)], + }), + username: new FormControl('', { + nonNullable: true, + validators: [Validators.required, Validators.minLength(3), Validators.pattern(/^[a-zA-Z0-9]+$/)], + }), + password: new FormControl('', { + nonNullable: true, + validators: [Validators.required, Validators.minLength(8)], + }), + organizationName: new FormControl('', { + nonNullable: true, + validators: [Validators.required, Validators.minLength(2)], + }), + }); + + public passwordVisible = false; + + public ngOnInit(): void { + this.store.dispatch(registrationActions.registrationResetAction()); + } + + public ngOnDestroy(): void { + this.store.dispatch(registrationActions.registrationResetAction()); + } + + public togglePasswordVisibility(): void { + this.passwordVisible = !this.passwordVisible; + } + + public getFieldError(fieldName: string): string | null { + const control = this.registrationFormGroup.get(fieldName); + if (!control || !control.invalid || !control.touched) { + return null; + } + if (control.errors?.['required']) { + return 'This field is required.'; + } + if (control.errors?.['email']) { + return 'Please enter a valid email address.'; + } + if (control.errors?.['minlength']) { + const requiredLength = control.errors['minlength'].requiredLength; + return `Must be at least ${requiredLength} characters.`; + } + if (control.errors?.['pattern']) { + if (fieldName === 'mobile') { + return 'Please enter a valid mobile number (10–15 digits).'; + } + if (fieldName === 'username') { + return 'Only letters and numbers are allowed.'; + } + } + return 'Invalid value.'; + } + + public login(): void { + this.store.dispatch(logInActions.logInAction()); + } + + public submitRegistration(): void { + if (this.registrationFormGroup.invalid) { + this.registrationFormGroup.markAllAsTouched(); + return; + } + const formValue = this.registrationFormGroup.getRawValue(); + this.store.dispatch( + registrationActions.registrationSubmitAction({ + payload: { + user: { + fname: formValue.firstName, + lname: formValue.lastName, + email: formValue.email, + mobile: formValue.mobile, + username: formValue.username, + password: formValue.password, + }, + client: { + name: formValue.organizationName, + }, + }, + }) + ); + } +} diff --git a/apps/36-blocks/src/app/website/security/security.component.html b/apps/36-blocks/src/app/website/security/security.component.html index b1a0d1f9..c0616ff5 100644 --- a/apps/36-blocks/src/app/website/security/security.component.html +++ b/apps/36-blocks/src/app/website/security/security.component.html @@ -1,26 +1,6 @@
-

-

Terms of Service

diff --git a/apps/36-blocks/src/app/website/website.routes.ts b/apps/36-blocks/src/app/website/website.routes.ts index 983247d7..41486725 100644 --- a/apps/36-blocks/src/app/website/website.routes.ts +++ b/apps/36-blocks/src/app/website/website.routes.ts @@ -36,6 +36,10 @@ export const websiteRoutes: Route[] = [ path: 'contact', loadComponent: () => import('./contact/contact.component').then((c) => c.ContactComponent), }, + { + path: 'register', + loadComponent: () => import('./register/register-page.component').then((c) => c.RegisterPageComponent), + }, ], }, ]; diff --git a/libs/services/proxy/users/src/lib/services-proxy-users.module.ts b/libs/services/proxy/users/src/lib/services-proxy-users.module.ts index 1d31eb71..dd68c503 100644 --- a/libs/services/proxy/users/src/lib/services-proxy-users.module.ts +++ b/libs/services/proxy/users/src/lib/services-proxy-users.module.ts @@ -94,4 +94,8 @@ export class UsersService { public register(formData: any): Observable { return this.httpNoAuth.post(UsersUrl.register(this.baseURL), formData, this.options); } + + public exchangeToken(code: string): Observable<{ token: string }> { + return this.httpNoAuth.post<{ token: string }>(UsersUrl.exchangeToken(this.baseURL), { code }, this.options); + } } diff --git a/libs/urls/users-urls/src/index.ts b/libs/urls/users-urls/src/index.ts index 869772af..21f9368e 100644 --- a/libs/urls/users-urls/src/index.ts +++ b/libs/urls/users-urls/src/index.ts @@ -3,6 +3,7 @@ import { createUrl } from '@proxy/service'; export const UsersUrl = { getUsers: (baseUrl) => createUrl(baseUrl, 'clientUsers'), register: (baseUrl) => createUrl(baseUrl, 'register'), + exchangeToken: (baseUrl) => createUrl(baseUrl, 'exchange-token'), getRoles: (baseUrl) => createUrl(baseUrl, ':referenceId/cRoles'), createRole: (baseUrl) => createUrl(baseUrl, ':referenceId/cRoles'), updateRole: (baseUrl) => createUrl(baseUrl, ':referenceId/cRoles/:id'), From 5a534f35736a8abf9e1359bf49fbae201997ae52 Mon Sep 17 00:00:00 2001 From: Giddh's Black Tiger Date: Thu, 16 Apr 2026 19:11:48 +0530 Subject: [PATCH 02/16] feat(onboarding): CDK virtual scroll, flag images, native names, placeholders, centered layout --- apps/36-blocks/src/app/app.component.ts | 3 +- apps/36-blocks/src/app/app.routes.ts | 4 + .../app/panel/layout/layout.component.html | 1 + .../src/app/panel/layout/layout.component.ts | 15 + .../src/app/panel/layout/side-nav.service.ts | 1 + .../onboarding/onboarding.component.html | 255 +- .../panel/onboarding/onboarding.component.ts | 178 +- apps/36-blocks/src/app/panel/panel.routes.ts | 4 - .../website/home/ngrx/actions/login.action.ts | 9 + .../home/ngrx/actions/registration.action.ts | 13 +- .../home/ngrx/effects/login.effects.ts | 50 + .../home/ngrx/effects/registration.effects.ts | 2 +- .../layout/website-layout.component.html | 14 +- .../website/login/google-one-tap.service.ts | 129 + .../website/login/login-page.component.html | 249 ++ .../website/login/login-page.component.scss | 3 + .../app/website/login/login-page.component.ts | 139 + .../register/register-page.component.html | 139 +- .../register/register-page.component.ts | 46 +- .../src/app/website/website.routes.ts | 4 + apps/36-blocks/src/assets/images/flags/ad.png | Bin 0 -> 600 bytes apps/36-blocks/src/assets/images/flags/ae.png | Bin 0 -> 132 bytes apps/36-blocks/src/assets/images/flags/af.png | Bin 0 -> 1278 bytes apps/36-blocks/src/assets/images/flags/ag.png | Bin 0 -> 708 bytes apps/36-blocks/src/assets/images/flags/ai.png | Bin 0 -> 650 bytes apps/36-blocks/src/assets/images/flags/al.png | Bin 0 -> 643 bytes apps/36-blocks/src/assets/images/flags/am.png | Bin 0 -> 121 bytes apps/36-blocks/src/assets/images/flags/ao.png | Bin 0 -> 550 bytes apps/36-blocks/src/assets/images/flags/aq.png | Bin 0 -> 481 bytes apps/36-blocks/src/assets/images/flags/ar.png | Bin 0 -> 335 bytes apps/36-blocks/src/assets/images/flags/as.png | Bin 0 -> 752 bytes apps/36-blocks/src/assets/images/flags/at.png | Bin 0 -> 109 bytes apps/36-blocks/src/assets/images/flags/au.png | Bin 0 -> 592 bytes apps/36-blocks/src/assets/images/flags/aw.png | Bin 0 -> 270 bytes apps/36-blocks/src/assets/images/flags/ax.png | Bin 0 -> 168 bytes apps/36-blocks/src/assets/images/flags/az.png | Bin 0 -> 262 bytes apps/36-blocks/src/assets/images/flags/ba.png | Bin 0 -> 346 bytes apps/36-blocks/src/assets/images/flags/bb.png | Bin 0 -> 349 bytes apps/36-blocks/src/assets/images/flags/bd.png | Bin 0 -> 276 bytes apps/36-blocks/src/assets/images/flags/be.png | Bin 0 -> 127 bytes apps/36-blocks/src/assets/images/flags/bf.png | Bin 0 -> 249 bytes apps/36-blocks/src/assets/images/flags/bg.png | Bin 0 -> 105 bytes apps/36-blocks/src/assets/images/flags/bh.png | Bin 0 -> 329 bytes apps/36-blocks/src/assets/images/flags/bi.png | Bin 0 -> 643 bytes apps/36-blocks/src/assets/images/flags/bj.png | Bin 0 -> 115 bytes apps/36-blocks/src/assets/images/flags/bm.png | Bin 0 -> 971 bytes apps/36-blocks/src/assets/images/flags/bn.png | Bin 0 -> 995 bytes apps/36-blocks/src/assets/images/flags/bo.png | Bin 0 -> 630 bytes apps/36-blocks/src/assets/images/flags/bq.png | Bin 0 -> 886 bytes apps/36-blocks/src/assets/images/flags/br.png | Bin 0 -> 816 bytes apps/36-blocks/src/assets/images/flags/bs.png | Bin 0 -> 285 bytes apps/36-blocks/src/assets/images/flags/bt.png | Bin 0 -> 1086 bytes apps/36-blocks/src/assets/images/flags/bv.png | Bin 0 -> 192 bytes apps/36-blocks/src/assets/images/flags/bw.png | Bin 0 -> 134 bytes apps/36-blocks/src/assets/images/flags/by.png | Bin 0 -> 418 bytes apps/36-blocks/src/assets/images/flags/bz.png | Bin 0 -> 1017 bytes apps/36-blocks/src/assets/images/flags/ca.png | Bin 0 -> 404 bytes apps/36-blocks/src/assets/images/flags/cc.png | Bin 0 -> 599 bytes apps/36-blocks/src/assets/images/flags/cd.png | Bin 0 -> 447 bytes apps/36-blocks/src/assets/images/flags/cf.png | Bin 0 -> 282 bytes apps/36-blocks/src/assets/images/flags/cg.png | Bin 0 -> 310 bytes apps/36-blocks/src/assets/images/flags/ch.png | Bin 0 -> 135 bytes apps/36-blocks/src/assets/images/flags/ci.png | Bin 0 -> 122 bytes apps/36-blocks/src/assets/images/flags/ck.png | Bin 0 -> 781 bytes apps/36-blocks/src/assets/images/flags/cl.png | Bin 0 -> 228 bytes apps/36-blocks/src/assets/images/flags/cm.png | Bin 0 -> 228 bytes apps/36-blocks/src/assets/images/flags/cn.png | Bin 0 -> 315 bytes apps/36-blocks/src/assets/images/flags/co.png | Bin 0 -> 125 bytes apps/36-blocks/src/assets/images/flags/cr.png | Bin 0 -> 398 bytes apps/36-blocks/src/assets/images/flags/cu.png | Bin 0 -> 387 bytes apps/36-blocks/src/assets/images/flags/cv.png | Bin 0 -> 334 bytes apps/36-blocks/src/assets/images/flags/cw.png | Bin 0 -> 239 bytes apps/36-blocks/src/assets/images/flags/cx.png | Bin 0 -> 700 bytes apps/36-blocks/src/assets/images/flags/cy.png | Bin 0 -> 559 bytes apps/36-blocks/src/assets/images/flags/cz.png | Bin 0 -> 363 bytes apps/36-blocks/src/assets/images/flags/de.png | Bin 0 -> 105 bytes apps/36-blocks/src/assets/images/flags/dj.png | Bin 0 -> 506 bytes apps/36-blocks/src/assets/images/flags/dk.png | Bin 0 -> 148 bytes apps/36-blocks/src/assets/images/flags/dm.png | Bin 0 -> 517 bytes apps/36-blocks/src/assets/images/flags/do.png | Bin 0 -> 396 bytes apps/36-blocks/src/assets/images/flags/dz.png | Bin 0 -> 399 bytes apps/36-blocks/src/assets/images/flags/ec.png | Bin 0 -> 933 bytes apps/36-blocks/src/assets/images/flags/ee.png | Bin 0 -> 106 bytes apps/36-blocks/src/assets/images/flags/eg.png | Bin 0 -> 291 bytes apps/36-blocks/src/assets/images/flags/eh.png | Bin 0 -> 396 bytes apps/36-blocks/src/assets/images/flags/er.png | Bin 0 -> 545 bytes apps/36-blocks/src/assets/images/flags/es.png | Bin 0 -> 673 bytes apps/36-blocks/src/assets/images/flags/et.png | Bin 0 -> 571 bytes apps/36-blocks/src/assets/images/flags/fi.png | Bin 0 -> 134 bytes apps/36-blocks/src/assets/images/flags/fj.png | Bin 0 -> 903 bytes apps/36-blocks/src/assets/images/flags/fk.png | Bin 0 -> 1151 bytes apps/36-blocks/src/assets/images/flags/fm.png | Bin 0 -> 217 bytes apps/36-blocks/src/assets/images/flags/fo.png | Bin 0 -> 188 bytes apps/36-blocks/src/assets/images/flags/fr.png | Bin 0 -> 123 bytes apps/36-blocks/src/assets/images/flags/ga.png | Bin 0 -> 106 bytes apps/36-blocks/src/assets/images/flags/gb.png | Bin 0 -> 395 bytes apps/36-blocks/src/assets/images/flags/gd.png | Bin 0 -> 644 bytes apps/36-blocks/src/assets/images/flags/ge.png | Bin 0 -> 393 bytes apps/36-blocks/src/assets/images/flags/gf.png | Bin 0 -> 468 bytes apps/36-blocks/src/assets/images/flags/gg.png | Bin 0 -> 236 bytes apps/36-blocks/src/assets/images/flags/gh.png | Bin 0 -> 267 bytes apps/36-blocks/src/assets/images/flags/gi.png | Bin 0 -> 615 bytes apps/36-blocks/src/assets/images/flags/gl.png | Bin 0 -> 371 bytes apps/36-blocks/src/assets/images/flags/gm.png | Bin 0 -> 145 bytes apps/36-blocks/src/assets/images/flags/gn.png | Bin 0 -> 122 bytes apps/36-blocks/src/assets/images/flags/gp.png | Bin 0 -> 1070 bytes apps/36-blocks/src/assets/images/flags/gq.png | Bin 0 -> 634 bytes apps/36-blocks/src/assets/images/flags/gr.png | Bin 0 -> 208 bytes apps/36-blocks/src/assets/images/flags/gs.png | Bin 0 -> 1269 bytes apps/36-blocks/src/assets/images/flags/gt.png | Bin 0 -> 540 bytes apps/36-blocks/src/assets/images/flags/gu.png | Bin 0 -> 634 bytes apps/36-blocks/src/assets/images/flags/gw.png | Bin 0 -> 202 bytes apps/36-blocks/src/assets/images/flags/gy.png | Bin 0 -> 498 bytes apps/36-blocks/src/assets/images/flags/hk.png | Bin 0 -> 506 bytes apps/36-blocks/src/assets/images/flags/hm.png | Bin 0 -> 588 bytes apps/36-blocks/src/assets/images/flags/hn.png | Bin 0 -> 233 bytes apps/36-blocks/src/assets/images/flags/hr.png | Bin 0 -> 639 bytes apps/36-blocks/src/assets/images/flags/ht.png | Bin 0 -> 871 bytes apps/36-blocks/src/assets/images/flags/hu.png | Bin 0 -> 119 bytes apps/36-blocks/src/assets/images/flags/id.png | Bin 0 -> 105 bytes apps/36-blocks/src/assets/images/flags/ie.png | Bin 0 -> 119 bytes apps/36-blocks/src/assets/images/flags/il.png | Bin 0 -> 301 bytes apps/36-blocks/src/assets/images/flags/im.png | Bin 0 -> 667 bytes apps/36-blocks/src/assets/images/flags/in.png | Bin 0 -> 354 bytes apps/36-blocks/src/assets/images/flags/io.png | Bin 0 -> 1631 bytes apps/36-blocks/src/assets/images/flags/iq.png | Bin 0 -> 319 bytes apps/36-blocks/src/assets/images/flags/ir.png | Bin 0 -> 451 bytes apps/36-blocks/src/assets/images/flags/is.png | Bin 0 -> 185 bytes apps/36-blocks/src/assets/images/flags/it.png | Bin 0 -> 122 bytes apps/36-blocks/src/assets/images/flags/je.png | Bin 0 -> 765 bytes apps/36-blocks/src/assets/images/flags/jm.png | Bin 0 -> 293 bytes apps/36-blocks/src/assets/images/flags/jo.png | Bin 0 -> 287 bytes apps/36-blocks/src/assets/images/flags/jp.png | Bin 0 -> 353 bytes apps/36-blocks/src/assets/images/flags/ke.png | Bin 0 -> 655 bytes apps/36-blocks/src/assets/images/flags/kg.png | Bin 0 -> 615 bytes apps/36-blocks/src/assets/images/flags/kh.png | Bin 0 -> 647 bytes apps/36-blocks/src/assets/images/flags/ki.png | Bin 0 -> 907 bytes apps/36-blocks/src/assets/images/flags/km.png | Bin 0 -> 529 bytes apps/36-blocks/src/assets/images/flags/kn.png | Bin 0 -> 765 bytes apps/36-blocks/src/assets/images/flags/kp.png | Bin 0 -> 321 bytes apps/36-blocks/src/assets/images/flags/kr.png | Bin 0 -> 972 bytes apps/36-blocks/src/assets/images/flags/kw.png | Bin 0 -> 233 bytes apps/36-blocks/src/assets/images/flags/ky.png | Bin 0 -> 977 bytes apps/36-blocks/src/assets/images/flags/kz.png | Bin 0 -> 552 bytes apps/36-blocks/src/assets/images/flags/la.png | Bin 0 -> 264 bytes apps/36-blocks/src/assets/images/flags/lb.png | Bin 0 -> 432 bytes apps/36-blocks/src/assets/images/flags/lc.png | Bin 0 -> 499 bytes apps/36-blocks/src/assets/images/flags/li.png | Bin 0 -> 399 bytes apps/36-blocks/src/assets/images/flags/lk.png | Bin 0 -> 673 bytes apps/36-blocks/src/assets/images/flags/lr.png | Bin 0 -> 278 bytes apps/36-blocks/src/assets/images/flags/ls.png | Bin 0 -> 319 bytes apps/36-blocks/src/assets/images/flags/lt.png | Bin 0 -> 105 bytes apps/36-blocks/src/assets/images/flags/lu.png | Bin 0 -> 105 bytes apps/36-blocks/src/assets/images/flags/lv.png | Bin 0 -> 94 bytes apps/36-blocks/src/assets/images/flags/ly.png | Bin 0 -> 226 bytes apps/36-blocks/src/assets/images/flags/ma.png | Bin 0 -> 304 bytes apps/36-blocks/src/assets/images/flags/mc.png | Bin 0 -> 95 bytes apps/36-blocks/src/assets/images/flags/md.png | Bin 0 -> 610 bytes apps/36-blocks/src/assets/images/flags/me.png | Bin 0 -> 529 bytes apps/36-blocks/src/assets/images/flags/mf.png | Bin 0 -> 123 bytes apps/36-blocks/src/assets/images/flags/mg.png | Bin 0 -> 132 bytes apps/36-blocks/src/assets/images/flags/mh.png | Bin 0 -> 641 bytes apps/36-blocks/src/assets/images/flags/mk.png | Bin 0 -> 545 bytes apps/36-blocks/src/assets/images/flags/ml.png | Bin 0 -> 123 bytes apps/36-blocks/src/assets/images/flags/mm.png | Bin 0 -> 463 bytes apps/36-blocks/src/assets/images/flags/mn.png | Bin 0 -> 304 bytes apps/36-blocks/src/assets/images/flags/mo.png | Bin 0 -> 616 bytes apps/36-blocks/src/assets/images/flags/mp.png | Bin 0 -> 1445 bytes apps/36-blocks/src/assets/images/flags/mq.png | Bin 0 -> 354 bytes apps/36-blocks/src/assets/images/flags/mr.png | Bin 0 -> 379 bytes apps/36-blocks/src/assets/images/flags/ms.png | Bin 0 -> 772 bytes apps/36-blocks/src/assets/images/flags/mt.png | Bin 0 -> 266 bytes apps/36-blocks/src/assets/images/flags/mu.png | Bin 0 -> 138 bytes apps/36-blocks/src/assets/images/flags/mv.png | Bin 0 -> 243 bytes apps/36-blocks/src/assets/images/flags/mw.png | Bin 0 -> 349 bytes apps/36-blocks/src/assets/images/flags/mx.png | Bin 0 -> 562 bytes apps/36-blocks/src/assets/images/flags/my.png | Bin 0 -> 398 bytes apps/36-blocks/src/assets/images/flags/mz.png | Bin 0 -> 664 bytes apps/36-blocks/src/assets/images/flags/na.png | Bin 0 -> 780 bytes apps/36-blocks/src/assets/images/flags/nc.png | Bin 0 -> 609 bytes apps/36-blocks/src/assets/images/flags/ne.png | Bin 0 -> 263 bytes apps/36-blocks/src/assets/images/flags/nf.png | Bin 0 -> 460 bytes apps/36-blocks/src/assets/images/flags/ng.png | Bin 0 -> 105 bytes apps/36-blocks/src/assets/images/flags/ni.png | Bin 0 -> 360 bytes apps/36-blocks/src/assets/images/flags/nl.png | Bin 0 -> 127 bytes apps/36-blocks/src/assets/images/flags/no.png | Bin 0 -> 192 bytes apps/36-blocks/src/assets/images/flags/np.png | Bin 0 -> 1032 bytes apps/36-blocks/src/assets/images/flags/nr.png | Bin 0 -> 255 bytes apps/36-blocks/src/assets/images/flags/nu.png | Bin 0 -> 557 bytes apps/36-blocks/src/assets/images/flags/nz.png | Bin 0 -> 536 bytes apps/36-blocks/src/assets/images/flags/om.png | Bin 0 -> 261 bytes apps/36-blocks/src/assets/images/flags/pa.png | Bin 0 -> 361 bytes apps/36-blocks/src/assets/images/flags/pe.png | Bin 0 -> 107 bytes apps/36-blocks/src/assets/images/flags/pf.png | Bin 0 -> 645 bytes apps/36-blocks/src/assets/images/flags/pg.png | Bin 0 -> 784 bytes apps/36-blocks/src/assets/images/flags/ph.png | Bin 0 -> 564 bytes apps/36-blocks/src/assets/images/flags/pk.png | Bin 0 -> 453 bytes apps/36-blocks/src/assets/images/flags/pl.png | Bin 0 -> 94 bytes apps/36-blocks/src/assets/images/flags/pn.png | Bin 0 -> 1152 bytes apps/36-blocks/src/assets/images/flags/pr.png | Bin 0 -> 469 bytes apps/36-blocks/src/assets/images/flags/ps.png | Bin 0 -> 304 bytes apps/36-blocks/src/assets/images/flags/pt.png | Bin 0 -> 893 bytes apps/36-blocks/src/assets/images/flags/pw.png | Bin 0 -> 307 bytes apps/36-blocks/src/assets/images/flags/py.png | Bin 0 -> 287 bytes apps/36-blocks/src/assets/images/flags/qa.png | Bin 0 -> 201 bytes apps/36-blocks/src/assets/images/flags/re.png | Bin 0 -> 784 bytes apps/36-blocks/src/assets/images/flags/ro.png | Bin 0 -> 122 bytes apps/36-blocks/src/assets/images/flags/rs.png | Bin 0 -> 934 bytes apps/36-blocks/src/assets/images/flags/ru.png | Bin 0 -> 125 bytes apps/36-blocks/src/assets/images/flags/rw.png | Bin 0 -> 281 bytes apps/36-blocks/src/assets/images/flags/sa.png | Bin 0 -> 566 bytes apps/36-blocks/src/assets/images/flags/sb.png | Bin 0 -> 457 bytes apps/36-blocks/src/assets/images/flags/sc.png | Bin 0 -> 492 bytes apps/36-blocks/src/assets/images/flags/sd.png | Bin 0 -> 299 bytes apps/36-blocks/src/assets/images/flags/se.png | Bin 0 -> 100 bytes apps/36-blocks/src/assets/images/flags/sg.png | Bin 0 -> 354 bytes apps/36-blocks/src/assets/images/flags/sh.png | Bin 0 -> 845 bytes apps/36-blocks/src/assets/images/flags/si.png | Bin 0 -> 313 bytes apps/36-blocks/src/assets/images/flags/sj.png | Bin 0 -> 192 bytes apps/36-blocks/src/assets/images/flags/sk.png | Bin 0 -> 524 bytes apps/36-blocks/src/assets/images/flags/sl.png | Bin 0 -> 127 bytes apps/36-blocks/src/assets/images/flags/sm.png | Bin 0 -> 1130 bytes apps/36-blocks/src/assets/images/flags/sn.png | Bin 0 -> 241 bytes apps/36-blocks/src/assets/images/flags/so.png | Bin 0 -> 264 bytes apps/36-blocks/src/assets/images/flags/sr.png | Bin 0 -> 281 bytes apps/36-blocks/src/assets/images/flags/ss.png | Bin 0 -> 437 bytes apps/36-blocks/src/assets/images/flags/st.png | Bin 0 -> 342 bytes apps/36-blocks/src/assets/images/flags/sv.png | Bin 0 -> 479 bytes apps/36-blocks/src/assets/images/flags/sx.png | Bin 0 -> 831 bytes apps/36-blocks/src/assets/images/flags/sy.png | Bin 0 -> 253 bytes apps/36-blocks/src/assets/images/flags/sz.png | Bin 0 -> 809 bytes apps/36-blocks/src/assets/images/flags/tc.png | Bin 0 -> 775 bytes apps/36-blocks/src/assets/images/flags/td.png | Bin 0 -> 122 bytes apps/36-blocks/src/assets/images/flags/tf.png | Bin 0 -> 359 bytes apps/36-blocks/src/assets/images/flags/tg.png | Bin 0 -> 314 bytes apps/36-blocks/src/assets/images/flags/th.png | Bin 0 -> 137 bytes apps/36-blocks/src/assets/images/flags/tj.png | Bin 0 -> 264 bytes apps/36-blocks/src/assets/images/flags/tk.png | Bin 0 -> 577 bytes apps/36-blocks/src/assets/images/flags/tl.png | Bin 0 -> 382 bytes apps/36-blocks/src/assets/images/flags/tm.png | Bin 0 -> 1379 bytes apps/36-blocks/src/assets/images/flags/tn.png | Bin 0 -> 466 bytes apps/36-blocks/src/assets/images/flags/to.png | Bin 0 -> 158 bytes apps/36-blocks/src/assets/images/flags/tr.png | Bin 0 -> 377 bytes apps/36-blocks/src/assets/images/flags/tt.png | Bin 0 -> 653 bytes apps/36-blocks/src/assets/images/flags/tv.png | Bin 0 -> 704 bytes apps/36-blocks/src/assets/images/flags/tw.png | Bin 0 -> 359 bytes apps/36-blocks/src/assets/images/flags/tz.png | Bin 0 -> 442 bytes apps/36-blocks/src/assets/images/flags/ua.png | Bin 0 -> 105 bytes apps/36-blocks/src/assets/images/flags/ug.png | Bin 0 -> 452 bytes apps/36-blocks/src/assets/images/flags/um.png | Bin 0 -> 430 bytes apps/36-blocks/src/assets/images/flags/us.png | Bin 0 -> 430 bytes apps/36-blocks/src/assets/images/flags/uy.png | Bin 0 -> 504 bytes apps/36-blocks/src/assets/images/flags/uz.png | Bin 0 -> 242 bytes apps/36-blocks/src/assets/images/flags/va.png | Bin 0 -> 1113 bytes apps/36-blocks/src/assets/images/flags/vc.png | Bin 0 -> 316 bytes apps/36-blocks/src/assets/images/flags/ve.png | Bin 0 -> 297 bytes apps/36-blocks/src/assets/images/flags/vg.png | Bin 0 -> 938 bytes apps/36-blocks/src/assets/images/flags/vi.png | Bin 0 -> 1992 bytes apps/36-blocks/src/assets/images/flags/vn.png | Bin 0 -> 335 bytes apps/36-blocks/src/assets/images/flags/vu.png | Bin 0 -> 660 bytes apps/36-blocks/src/assets/images/flags/ws.png | Bin 0 -> 240 bytes apps/36-blocks/src/assets/images/flags/ye.png | Bin 0 -> 127 bytes apps/36-blocks/src/assets/images/flags/za.png | Bin 0 -> 543 bytes apps/36-blocks/src/assets/images/flags/zm.png | Bin 0 -> 292 bytes apps/36-blocks/src/assets/images/flags/zw.png | Bin 0 -> 585 bytes apps/shared/assets/utils/countries-info.ts | 2261 +++++++++++++++++ .../src/lib/services-proxy-users.module.ts | 16 + libs/urls/users-urls/src/index.ts | 2 + 268 files changed, 3235 insertions(+), 302 deletions(-) create mode 100644 apps/36-blocks/src/app/website/login/google-one-tap.service.ts create mode 100644 apps/36-blocks/src/app/website/login/login-page.component.html create mode 100644 apps/36-blocks/src/app/website/login/login-page.component.scss create mode 100644 apps/36-blocks/src/app/website/login/login-page.component.ts create mode 100644 apps/36-blocks/src/assets/images/flags/ad.png create mode 100644 apps/36-blocks/src/assets/images/flags/ae.png create mode 100644 apps/36-blocks/src/assets/images/flags/af.png create mode 100644 apps/36-blocks/src/assets/images/flags/ag.png create mode 100644 apps/36-blocks/src/assets/images/flags/ai.png create mode 100644 apps/36-blocks/src/assets/images/flags/al.png create mode 100644 apps/36-blocks/src/assets/images/flags/am.png create mode 100644 apps/36-blocks/src/assets/images/flags/ao.png create mode 100644 apps/36-blocks/src/assets/images/flags/aq.png create mode 100644 apps/36-blocks/src/assets/images/flags/ar.png create mode 100644 apps/36-blocks/src/assets/images/flags/as.png create mode 100644 apps/36-blocks/src/assets/images/flags/at.png create mode 100644 apps/36-blocks/src/assets/images/flags/au.png create mode 100644 apps/36-blocks/src/assets/images/flags/aw.png create mode 100644 apps/36-blocks/src/assets/images/flags/ax.png create mode 100644 apps/36-blocks/src/assets/images/flags/az.png create mode 100644 apps/36-blocks/src/assets/images/flags/ba.png create mode 100644 apps/36-blocks/src/assets/images/flags/bb.png create mode 100644 apps/36-blocks/src/assets/images/flags/bd.png create mode 100644 apps/36-blocks/src/assets/images/flags/be.png create mode 100644 apps/36-blocks/src/assets/images/flags/bf.png create mode 100644 apps/36-blocks/src/assets/images/flags/bg.png create mode 100644 apps/36-blocks/src/assets/images/flags/bh.png create mode 100644 apps/36-blocks/src/assets/images/flags/bi.png create mode 100644 apps/36-blocks/src/assets/images/flags/bj.png create mode 100644 apps/36-blocks/src/assets/images/flags/bm.png create mode 100644 apps/36-blocks/src/assets/images/flags/bn.png create mode 100644 apps/36-blocks/src/assets/images/flags/bo.png create mode 100644 apps/36-blocks/src/assets/images/flags/bq.png create mode 100644 apps/36-blocks/src/assets/images/flags/br.png create mode 100644 apps/36-blocks/src/assets/images/flags/bs.png create mode 100644 apps/36-blocks/src/assets/images/flags/bt.png create mode 100644 apps/36-blocks/src/assets/images/flags/bv.png create mode 100644 apps/36-blocks/src/assets/images/flags/bw.png create mode 100644 apps/36-blocks/src/assets/images/flags/by.png create mode 100644 apps/36-blocks/src/assets/images/flags/bz.png create mode 100644 apps/36-blocks/src/assets/images/flags/ca.png create mode 100644 apps/36-blocks/src/assets/images/flags/cc.png create mode 100644 apps/36-blocks/src/assets/images/flags/cd.png create mode 100644 apps/36-blocks/src/assets/images/flags/cf.png create mode 100644 apps/36-blocks/src/assets/images/flags/cg.png create mode 100644 apps/36-blocks/src/assets/images/flags/ch.png create mode 100644 apps/36-blocks/src/assets/images/flags/ci.png create mode 100644 apps/36-blocks/src/assets/images/flags/ck.png create mode 100644 apps/36-blocks/src/assets/images/flags/cl.png create mode 100644 apps/36-blocks/src/assets/images/flags/cm.png create mode 100644 apps/36-blocks/src/assets/images/flags/cn.png create mode 100644 apps/36-blocks/src/assets/images/flags/co.png create mode 100644 apps/36-blocks/src/assets/images/flags/cr.png create mode 100644 apps/36-blocks/src/assets/images/flags/cu.png create mode 100644 apps/36-blocks/src/assets/images/flags/cv.png create mode 100644 apps/36-blocks/src/assets/images/flags/cw.png create mode 100644 apps/36-blocks/src/assets/images/flags/cx.png create mode 100644 apps/36-blocks/src/assets/images/flags/cy.png create mode 100644 apps/36-blocks/src/assets/images/flags/cz.png create mode 100644 apps/36-blocks/src/assets/images/flags/de.png create mode 100644 apps/36-blocks/src/assets/images/flags/dj.png create mode 100644 apps/36-blocks/src/assets/images/flags/dk.png create mode 100644 apps/36-blocks/src/assets/images/flags/dm.png create mode 100644 apps/36-blocks/src/assets/images/flags/do.png create mode 100644 apps/36-blocks/src/assets/images/flags/dz.png create mode 100644 apps/36-blocks/src/assets/images/flags/ec.png create mode 100644 apps/36-blocks/src/assets/images/flags/ee.png create mode 100644 apps/36-blocks/src/assets/images/flags/eg.png create mode 100644 apps/36-blocks/src/assets/images/flags/eh.png create mode 100644 apps/36-blocks/src/assets/images/flags/er.png create mode 100644 apps/36-blocks/src/assets/images/flags/es.png create mode 100644 apps/36-blocks/src/assets/images/flags/et.png create mode 100644 apps/36-blocks/src/assets/images/flags/fi.png create mode 100644 apps/36-blocks/src/assets/images/flags/fj.png create mode 100644 apps/36-blocks/src/assets/images/flags/fk.png create mode 100644 apps/36-blocks/src/assets/images/flags/fm.png create mode 100644 apps/36-blocks/src/assets/images/flags/fo.png create mode 100644 apps/36-blocks/src/assets/images/flags/fr.png create mode 100644 apps/36-blocks/src/assets/images/flags/ga.png create mode 100644 apps/36-blocks/src/assets/images/flags/gb.png create mode 100644 apps/36-blocks/src/assets/images/flags/gd.png create mode 100644 apps/36-blocks/src/assets/images/flags/ge.png create mode 100644 apps/36-blocks/src/assets/images/flags/gf.png create mode 100644 apps/36-blocks/src/assets/images/flags/gg.png create mode 100644 apps/36-blocks/src/assets/images/flags/gh.png create mode 100644 apps/36-blocks/src/assets/images/flags/gi.png create mode 100644 apps/36-blocks/src/assets/images/flags/gl.png create mode 100644 apps/36-blocks/src/assets/images/flags/gm.png create mode 100644 apps/36-blocks/src/assets/images/flags/gn.png create mode 100644 apps/36-blocks/src/assets/images/flags/gp.png create mode 100644 apps/36-blocks/src/assets/images/flags/gq.png create mode 100644 apps/36-blocks/src/assets/images/flags/gr.png create mode 100644 apps/36-blocks/src/assets/images/flags/gs.png create mode 100644 apps/36-blocks/src/assets/images/flags/gt.png create mode 100644 apps/36-blocks/src/assets/images/flags/gu.png create mode 100644 apps/36-blocks/src/assets/images/flags/gw.png create mode 100644 apps/36-blocks/src/assets/images/flags/gy.png create mode 100644 apps/36-blocks/src/assets/images/flags/hk.png create mode 100644 apps/36-blocks/src/assets/images/flags/hm.png create mode 100644 apps/36-blocks/src/assets/images/flags/hn.png create mode 100644 apps/36-blocks/src/assets/images/flags/hr.png create mode 100644 apps/36-blocks/src/assets/images/flags/ht.png create mode 100644 apps/36-blocks/src/assets/images/flags/hu.png create mode 100644 apps/36-blocks/src/assets/images/flags/id.png create mode 100644 apps/36-blocks/src/assets/images/flags/ie.png create mode 100644 apps/36-blocks/src/assets/images/flags/il.png create mode 100644 apps/36-blocks/src/assets/images/flags/im.png create mode 100644 apps/36-blocks/src/assets/images/flags/in.png create mode 100644 apps/36-blocks/src/assets/images/flags/io.png create mode 100644 apps/36-blocks/src/assets/images/flags/iq.png create mode 100644 apps/36-blocks/src/assets/images/flags/ir.png create mode 100644 apps/36-blocks/src/assets/images/flags/is.png create mode 100644 apps/36-blocks/src/assets/images/flags/it.png create mode 100644 apps/36-blocks/src/assets/images/flags/je.png create mode 100644 apps/36-blocks/src/assets/images/flags/jm.png create mode 100644 apps/36-blocks/src/assets/images/flags/jo.png create mode 100644 apps/36-blocks/src/assets/images/flags/jp.png create mode 100644 apps/36-blocks/src/assets/images/flags/ke.png create mode 100644 apps/36-blocks/src/assets/images/flags/kg.png create mode 100644 apps/36-blocks/src/assets/images/flags/kh.png create mode 100644 apps/36-blocks/src/assets/images/flags/ki.png create mode 100644 apps/36-blocks/src/assets/images/flags/km.png create mode 100644 apps/36-blocks/src/assets/images/flags/kn.png create mode 100644 apps/36-blocks/src/assets/images/flags/kp.png create mode 100644 apps/36-blocks/src/assets/images/flags/kr.png create mode 100644 apps/36-blocks/src/assets/images/flags/kw.png create mode 100644 apps/36-blocks/src/assets/images/flags/ky.png create mode 100644 apps/36-blocks/src/assets/images/flags/kz.png create mode 100644 apps/36-blocks/src/assets/images/flags/la.png create mode 100644 apps/36-blocks/src/assets/images/flags/lb.png create mode 100644 apps/36-blocks/src/assets/images/flags/lc.png create mode 100644 apps/36-blocks/src/assets/images/flags/li.png create mode 100644 apps/36-blocks/src/assets/images/flags/lk.png create mode 100644 apps/36-blocks/src/assets/images/flags/lr.png create mode 100644 apps/36-blocks/src/assets/images/flags/ls.png create mode 100644 apps/36-blocks/src/assets/images/flags/lt.png create mode 100644 apps/36-blocks/src/assets/images/flags/lu.png create mode 100644 apps/36-blocks/src/assets/images/flags/lv.png create mode 100644 apps/36-blocks/src/assets/images/flags/ly.png create mode 100644 apps/36-blocks/src/assets/images/flags/ma.png create mode 100644 apps/36-blocks/src/assets/images/flags/mc.png create mode 100644 apps/36-blocks/src/assets/images/flags/md.png create mode 100644 apps/36-blocks/src/assets/images/flags/me.png create mode 100644 apps/36-blocks/src/assets/images/flags/mf.png create mode 100644 apps/36-blocks/src/assets/images/flags/mg.png create mode 100644 apps/36-blocks/src/assets/images/flags/mh.png create mode 100644 apps/36-blocks/src/assets/images/flags/mk.png create mode 100644 apps/36-blocks/src/assets/images/flags/ml.png create mode 100644 apps/36-blocks/src/assets/images/flags/mm.png create mode 100644 apps/36-blocks/src/assets/images/flags/mn.png create mode 100644 apps/36-blocks/src/assets/images/flags/mo.png create mode 100644 apps/36-blocks/src/assets/images/flags/mp.png create mode 100644 apps/36-blocks/src/assets/images/flags/mq.png create mode 100644 apps/36-blocks/src/assets/images/flags/mr.png create mode 100644 apps/36-blocks/src/assets/images/flags/ms.png create mode 100644 apps/36-blocks/src/assets/images/flags/mt.png create mode 100644 apps/36-blocks/src/assets/images/flags/mu.png create mode 100644 apps/36-blocks/src/assets/images/flags/mv.png create mode 100644 apps/36-blocks/src/assets/images/flags/mw.png create mode 100644 apps/36-blocks/src/assets/images/flags/mx.png create mode 100644 apps/36-blocks/src/assets/images/flags/my.png create mode 100644 apps/36-blocks/src/assets/images/flags/mz.png create mode 100644 apps/36-blocks/src/assets/images/flags/na.png create mode 100644 apps/36-blocks/src/assets/images/flags/nc.png create mode 100644 apps/36-blocks/src/assets/images/flags/ne.png create mode 100644 apps/36-blocks/src/assets/images/flags/nf.png create mode 100644 apps/36-blocks/src/assets/images/flags/ng.png create mode 100644 apps/36-blocks/src/assets/images/flags/ni.png create mode 100644 apps/36-blocks/src/assets/images/flags/nl.png create mode 100644 apps/36-blocks/src/assets/images/flags/no.png create mode 100644 apps/36-blocks/src/assets/images/flags/np.png create mode 100644 apps/36-blocks/src/assets/images/flags/nr.png create mode 100644 apps/36-blocks/src/assets/images/flags/nu.png create mode 100644 apps/36-blocks/src/assets/images/flags/nz.png create mode 100644 apps/36-blocks/src/assets/images/flags/om.png create mode 100644 apps/36-blocks/src/assets/images/flags/pa.png create mode 100644 apps/36-blocks/src/assets/images/flags/pe.png create mode 100644 apps/36-blocks/src/assets/images/flags/pf.png create mode 100644 apps/36-blocks/src/assets/images/flags/pg.png create mode 100644 apps/36-blocks/src/assets/images/flags/ph.png create mode 100644 apps/36-blocks/src/assets/images/flags/pk.png create mode 100644 apps/36-blocks/src/assets/images/flags/pl.png create mode 100644 apps/36-blocks/src/assets/images/flags/pn.png create mode 100644 apps/36-blocks/src/assets/images/flags/pr.png create mode 100644 apps/36-blocks/src/assets/images/flags/ps.png create mode 100644 apps/36-blocks/src/assets/images/flags/pt.png create mode 100644 apps/36-blocks/src/assets/images/flags/pw.png create mode 100644 apps/36-blocks/src/assets/images/flags/py.png create mode 100644 apps/36-blocks/src/assets/images/flags/qa.png create mode 100644 apps/36-blocks/src/assets/images/flags/re.png create mode 100644 apps/36-blocks/src/assets/images/flags/ro.png create mode 100644 apps/36-blocks/src/assets/images/flags/rs.png create mode 100644 apps/36-blocks/src/assets/images/flags/ru.png create mode 100644 apps/36-blocks/src/assets/images/flags/rw.png create mode 100644 apps/36-blocks/src/assets/images/flags/sa.png create mode 100644 apps/36-blocks/src/assets/images/flags/sb.png create mode 100644 apps/36-blocks/src/assets/images/flags/sc.png create mode 100644 apps/36-blocks/src/assets/images/flags/sd.png create mode 100644 apps/36-blocks/src/assets/images/flags/se.png create mode 100644 apps/36-blocks/src/assets/images/flags/sg.png create mode 100644 apps/36-blocks/src/assets/images/flags/sh.png create mode 100644 apps/36-blocks/src/assets/images/flags/si.png create mode 100644 apps/36-blocks/src/assets/images/flags/sj.png create mode 100644 apps/36-blocks/src/assets/images/flags/sk.png create mode 100644 apps/36-blocks/src/assets/images/flags/sl.png create mode 100644 apps/36-blocks/src/assets/images/flags/sm.png create mode 100644 apps/36-blocks/src/assets/images/flags/sn.png create mode 100644 apps/36-blocks/src/assets/images/flags/so.png create mode 100644 apps/36-blocks/src/assets/images/flags/sr.png create mode 100644 apps/36-blocks/src/assets/images/flags/ss.png create mode 100644 apps/36-blocks/src/assets/images/flags/st.png create mode 100644 apps/36-blocks/src/assets/images/flags/sv.png create mode 100644 apps/36-blocks/src/assets/images/flags/sx.png create mode 100644 apps/36-blocks/src/assets/images/flags/sy.png create mode 100644 apps/36-blocks/src/assets/images/flags/sz.png create mode 100644 apps/36-blocks/src/assets/images/flags/tc.png create mode 100644 apps/36-blocks/src/assets/images/flags/td.png create mode 100644 apps/36-blocks/src/assets/images/flags/tf.png create mode 100644 apps/36-blocks/src/assets/images/flags/tg.png create mode 100644 apps/36-blocks/src/assets/images/flags/th.png create mode 100644 apps/36-blocks/src/assets/images/flags/tj.png create mode 100644 apps/36-blocks/src/assets/images/flags/tk.png create mode 100644 apps/36-blocks/src/assets/images/flags/tl.png create mode 100644 apps/36-blocks/src/assets/images/flags/tm.png create mode 100644 apps/36-blocks/src/assets/images/flags/tn.png create mode 100644 apps/36-blocks/src/assets/images/flags/to.png create mode 100644 apps/36-blocks/src/assets/images/flags/tr.png create mode 100644 apps/36-blocks/src/assets/images/flags/tt.png create mode 100644 apps/36-blocks/src/assets/images/flags/tv.png create mode 100644 apps/36-blocks/src/assets/images/flags/tw.png create mode 100644 apps/36-blocks/src/assets/images/flags/tz.png create mode 100644 apps/36-blocks/src/assets/images/flags/ua.png create mode 100644 apps/36-blocks/src/assets/images/flags/ug.png create mode 100644 apps/36-blocks/src/assets/images/flags/um.png create mode 100644 apps/36-blocks/src/assets/images/flags/us.png create mode 100644 apps/36-blocks/src/assets/images/flags/uy.png create mode 100644 apps/36-blocks/src/assets/images/flags/uz.png create mode 100644 apps/36-blocks/src/assets/images/flags/va.png create mode 100644 apps/36-blocks/src/assets/images/flags/vc.png create mode 100644 apps/36-blocks/src/assets/images/flags/ve.png create mode 100644 apps/36-blocks/src/assets/images/flags/vg.png create mode 100644 apps/36-blocks/src/assets/images/flags/vi.png create mode 100644 apps/36-blocks/src/assets/images/flags/vn.png create mode 100644 apps/36-blocks/src/assets/images/flags/vu.png create mode 100644 apps/36-blocks/src/assets/images/flags/ws.png create mode 100644 apps/36-blocks/src/assets/images/flags/ye.png create mode 100644 apps/36-blocks/src/assets/images/flags/za.png create mode 100644 apps/36-blocks/src/assets/images/flags/zm.png create mode 100644 apps/36-blocks/src/assets/images/flags/zw.png create mode 100644 apps/shared/assets/utils/countries-info.ts diff --git a/apps/36-blocks/src/app/app.component.ts b/apps/36-blocks/src/app/app.component.ts index a5fd3360..fcd9bdd2 100644 --- a/apps/36-blocks/src/app/app.component.ts +++ b/apps/36-blocks/src/app/app.component.ts @@ -126,12 +126,13 @@ export class AppComponent extends BaseComponent implements OnInit, OnDestroy { '/privacy', '/terms', '/register', + '/login', ]; const isOnWebsiteRoute = currentUrl === '/' || currentUrl === '' || websiteRoutes.some((route) => currentUrl.startsWith(route)); - const isOnboardingRoute = currentUrl.startsWith('/app/onboarding'); + const isOnboardingRoute = currentUrl.startsWith('/onboarding'); if (isOnWebsiteRoute && !isOnboardingRoute) { this.router.navigate(['/app/dashboard']); } diff --git a/apps/36-blocks/src/app/app.routes.ts b/apps/36-blocks/src/app/app.routes.ts index c167936d..b5f3a765 100644 --- a/apps/36-blocks/src/app/app.routes.ts +++ b/apps/36-blocks/src/app/app.routes.ts @@ -14,6 +14,10 @@ export const appRoutes: Route[] = [ path: '', loadChildren: () => import('./website/website.routes').then((r) => r.websiteRoutes), }, + { + path: 'onboarding', + loadComponent: () => import('./panel/onboarding/onboarding.component').then((c) => c.OnboardingComponent), + }, { path: 'app', loadChildren: () => import('./panel/panel.routes').then((r) => r.panelRoutes), diff --git a/apps/36-blocks/src/app/panel/layout/layout.component.html b/apps/36-blocks/src/app/panel/layout/layout.component.html index 6cb16af9..ce152ce8 100644 --- a/apps/36-blocks/src/app/panel/layout/layout.component.html +++ b/apps/36-blocks/src/app/panel/layout/layout.component.html @@ -3,6 +3,7 @@ class="flex flex-col transition-all duration-200 mat-drawer-content max-desktop:fixed max-desktop:z-[999] max-desktop:top-0 max-desktop:bottom-0 bg-color p-2" [class.mat-drawer-toggle-btn-hover]="sideNavService.isSideNavOpen()" [class]="!sideNavService.isSideNavOpen() ? 'overflow-hidden !w-[56px] p-1.5' : 'w-[260px]'" + [class.!hidden]="sideNavService.hideSidebar()" > @let clientSettings = clientSettings$ | async; @let clientList = clients$ | async; @let isMultipleClients = (clientList?.data?.length ?? 0) > 1; diff --git a/apps/36-blocks/src/app/panel/layout/layout.component.ts b/apps/36-blocks/src/app/panel/layout/layout.component.ts index 7435cb93..51a17045 100644 --- a/apps/36-blocks/src/app/panel/layout/layout.component.ts +++ b/apps/36-blocks/src/app/panel/layout/layout.component.ts @@ -38,6 +38,8 @@ import { environment } from '../../../environments/environment'; import { AuthService } from '@proxy/services/proxy/auth'; import { SideNavService } from './side-nav.service'; import { UiSettingsService } from './ui-settings.service'; +import { FeaturesService } from '@proxy/services/proxy/features'; +import { take } from 'rxjs/operators'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'proxy-layout', @@ -85,6 +87,7 @@ export class LayoutComponent extends BaseComponent implements OnInit, OnDestroy private cdr = inject(ChangeDetectorRef); public sideNavService = inject(SideNavService); private uiSettings = inject(UiSettingsService); + private featuresService = inject(FeaturesService); constructor() { super(); @@ -118,6 +121,18 @@ export class LayoutComponent extends BaseComponent implements OnInit, OnDestroy if (event?.url?.startsWith('/widget-preview')) { (window as any).closeChatbot?.(); } + if (event?.url?.includes('/features/create')) { + this.featuresService + .getFeature({ itemsPerPage: 1, pageNo: 1 }) + .pipe(take(1)) + .subscribe((res) => { + const hasFeatures = (res?.data?.totalEntityCount ?? 0) > 0; + this.sideNavService.hideSidebar.set(!hasFeatures); + this.cdr.markForCheck(); + }); + } else { + this.sideNavService.hideSidebar.set(false); + } this.cdr.markForCheck(); }); } diff --git a/apps/36-blocks/src/app/panel/layout/side-nav.service.ts b/apps/36-blocks/src/app/panel/layout/side-nav.service.ts index 191d511c..b39847ac 100644 --- a/apps/36-blocks/src/app/panel/layout/side-nav.service.ts +++ b/apps/36-blocks/src/app/panel/layout/side-nav.service.ts @@ -6,6 +6,7 @@ export class SideNavService { private uiSettings = inject(UiSettingsService); public isSideNavOpen = signal(this.uiSettings.sideNavOpen); + public hideSidebar = signal(false); public toggle(): void { const next = !this.isSideNavOpen(); diff --git a/apps/36-blocks/src/app/panel/onboarding/onboarding.component.html b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.html index 00cc75b1..502e5bf8 100644 --- a/apps/36-blocks/src/app/panel/onboarding/onboarding.component.html +++ b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.html @@ -1,52 +1,213 @@ -
- @if (onboardingError()) { - - +
diff --git a/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts index 6f873c1c..022fd209 100644 --- a/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts +++ b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts @@ -1,14 +1,16 @@ import { ChangeDetectionStrategy, Component, + ElementRef, + HostListener, + ViewChild, inject, - NgZone, OnDestroy, OnInit, - PLATFORM_ID, signal, } from '@angular/core'; -import { isPlatformBrowser } from '@angular/common'; +import { ReactiveFormsModule, FormControl, FormGroup, Validators } from '@angular/forms'; +import { ScrollingModule } from '@angular/cdk/scrolling'; import { ActivatedRoute, Router } from '@angular/router'; import { Actions, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; @@ -17,11 +19,12 @@ import { take, takeUntil } from 'rxjs/operators'; import { AuthService } from '@proxy/services/proxy/auth'; import { UsersService } from '@proxy/services/proxy/users'; import * as logInActions from '../../website/home/ngrx/actions/login.action'; +import { COUNTRIES_DATA, Country } from '../../../../../shared/assets/utils/countries-info'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'proxy-onboarding', - imports: [], + imports: [ReactiveFormsModule, ScrollingModule], templateUrl: './onboarding.component.html', styleUrl: './onboarding.component.scss', }) @@ -32,56 +35,145 @@ export class OnboardingComponent implements OnInit, OnDestroy { private readonly usersService = inject(UsersService); private readonly store = inject(Store); private readonly actions$ = inject(Actions); - private readonly platformId = inject(PLATFORM_ID); - private readonly ngZone = inject(NgZone); private readonly destroy$ = new Subject(); + public readonly onboardingSubmitting = signal(false); public readonly onboardingError = signal(null); - public readonly onboardingInProgress = signal(true); - public readonly redirectCountdown = signal(3); + public passwordVisible = false; - private redirectTimer: ReturnType | null = null; + private pendingJwtToken: string | null = null; - public ngOnInit(): void { - if (!isPlatformBrowser(this.platformId)) { - return; + public readonly allCountries: Country[] = COUNTRIES_DATA; + public selectedCountry: Country = COUNTRIES_DATA.find((country) => country.code === 'IN') ?? COUNTRIES_DATA[0]; + public readonly dialCodeDropdownOpen = signal(false); + public readonly dialCodeSearchQuery = signal(''); + + @ViewChild('dialCodeDropdownRef') private readonly dialCodeDropdownRef!: ElementRef; + + public get filteredCountries(): Country[] { + const query = this.dialCodeSearchQuery().trim().toLowerCase(); + if (!query) { + return this.allCountries; + } + return this.allCountries.filter( + (country) => + country.name.toLowerCase().includes(query) || + country.dialCode.includes(query) || + country.nativeName.toLowerCase().includes(query) + ); + } + + public toggleDialCodeDropdown(): void { + const isOpen = !this.dialCodeDropdownOpen(); + this.dialCodeDropdownOpen.set(isOpen); + if (isOpen) { + this.dialCodeSearchQuery.set(''); } + } - const verificationCode = this.activatedRoute.snapshot.queryParamMap.get('code'); + public selectCountry(country: Country): void { + this.selectedCountry = country; + this.dialCodeDropdownOpen.set(false); + this.dialCodeSearchQuery.set(''); + } + + public updateDialCodeSearch(value: string): void { + this.dialCodeSearchQuery.set(value); + } + + public trackCountryByCode(_index: number, country: Country): string { + return country.code; + } + + @HostListener('document:keydown.escape') + public closeDialCodeDropdownOnEscape(): void { + this.dialCodeDropdownOpen.set(false); + } + + @HostListener('document:click', ['$event']) + public closeDialCodeDropdownOnOutsideClick(event: MouseEvent): void { + if (this.dialCodeDropdownRef && !this.dialCodeDropdownRef.nativeElement.contains(event.target as Node)) { + this.dialCodeDropdownOpen.set(false); + } + } + + public readonly onboardingFormGroup = new FormGroup({ + name: new FormControl('', { + nonNullable: true, + validators: [Validators.required, Validators.minLength(2)], + }), + mobile: new FormControl('', { + nonNullable: true, + validators: [Validators.required, Validators.pattern(/^\d{10,15}$/)], + }), + organizationName: new FormControl('', { + nonNullable: true, + validators: [Validators.required, Validators.minLength(2)], + }), + }); + + public ngOnInit(): void { + this.pendingJwtToken = this.activatedRoute.snapshot.queryParamMap.get('token'); + } - if (!verificationCode) { - this.onboardingError.set('No verification code found. Please check your email link and try again.'); - this.onboardingInProgress.set(false); - this.redirectToHomeAfterDelay(); + public ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + public getFieldError(fieldName: string): string | null { + const control = this.onboardingFormGroup.get(fieldName); + if (!control || !control.invalid || !control.touched) { + return null; + } + if (control.errors?.['required']) { + return 'This field is required.'; + } + if (control.errors?.['minlength']) { + const requiredLength = control.errors['minlength'].requiredLength; + return `Must be at least ${requiredLength} characters.`; + } + if (control.errors?.['pattern'] && fieldName === 'mobile') { + return 'Please enter a valid mobile number (10\u201315 digits).'; + } + return 'Invalid value.'; + } + + public submitOnboarding(): void { + if (this.onboardingFormGroup.invalid) { + this.onboardingFormGroup.markAllAsTouched(); return; } + this.onboardingError.set(null); + this.onboardingSubmitting.set(true); + const formValue = this.onboardingFormGroup.getRawValue(); + const mobileWithDialCode = `${this.selectedCountry.dialCode}${formValue.mobile}`; this.usersService - .exchangeToken(verificationCode) + .submitOnboarding( + { name: formValue.name, mobile: mobileWithDialCode, organization_name: formValue.organizationName }, + this.pendingJwtToken ?? undefined + ) .pipe(take(1), takeUntil(this.destroy$)) .subscribe({ next: (response) => { - const jwtToken = response?.token; - if (!jwtToken) { - this.onboardingError.set('Verification failed: invalid server response. Please try again.'); - this.onboardingInProgress.set(false); - this.redirectToHomeAfterDelay(); - return; + const jwtToken = response?.data?.token || response?.token; + if (jwtToken) { + this.authService.setTokenSync(jwtToken); } - this.authService.setTokenSync(jwtToken); - this.actions$ .pipe(ofType(logInActions.authenticatedAction), take(1), takeUntil(this.destroy$)) .subscribe(() => { + this.onboardingSubmitting.set(false); this.router.navigate(['/app/features/create']); }); this.actions$ .pipe(ofType(logInActions.logInActionError), take(1), takeUntil(this.destroy$)) .subscribe(({ errors }) => { - this.onboardingError.set(errors?.join(' ') || 'Verification failed. Please try again.'); - this.onboardingInProgress.set(false); + this.onboardingSubmitting.set(false); + this.onboardingError.set(errors?.join(' ') || 'Something went wrong. Please try again.'); }); this.store.dispatch(logInActions.getUserAction()); @@ -92,36 +184,10 @@ export class OnboardingComponent implements OnInit, OnDestroy { errorBody?.errors?.message || errorBody?.data?.message || errorBody?.message || - 'Verification failed. Please try again.'; + 'Onboarding failed. Please try again.'; this.onboardingError.set(resolvedMessage); - this.onboardingInProgress.set(false); - this.redirectToHomeAfterDelay(); + this.onboardingSubmitting.set(false); }, }); } - - private redirectToHomeAfterDelay(): void { - this.redirectCountdown.set(3); - this.redirectTimer = this.ngZone.run(() => - setInterval(() => { - const remaining = this.redirectCountdown() - 1; - this.redirectCountdown.set(remaining); - if (remaining <= 0) { - if (this.redirectTimer) { - clearInterval(this.redirectTimer); - this.redirectTimer = null; - } - this.router.navigate(['/']); - } - }, 1000) - ); - } - - public ngOnDestroy(): void { - if (this.redirectTimer) { - clearInterval(this.redirectTimer); - } - this.destroy$.next(); - this.destroy$.complete(); - } } diff --git a/apps/36-blocks/src/app/panel/panel.routes.ts b/apps/36-blocks/src/app/panel/panel.routes.ts index a8d69618..7541981e 100644 --- a/apps/36-blocks/src/app/panel/panel.routes.ts +++ b/apps/36-blocks/src/app/panel/panel.routes.ts @@ -6,10 +6,6 @@ import { ProjectGuard } from './guard/project.guard'; const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['login']); export const panelRoutes: Route[] = [ - { - path: 'onboarding', - loadComponent: () => import('./onboarding/onboarding.component').then((c) => c.OnboardingComponent), - }, { path: '', loadComponent: () => import('./layout/layout.component').then((c) => c.LayoutComponent), diff --git a/apps/36-blocks/src/app/website/home/ngrx/actions/login.action.ts b/apps/36-blocks/src/app/website/home/ngrx/actions/login.action.ts index e358afe9..5289aefe 100755 --- a/apps/36-blocks/src/app/website/home/ngrx/actions/login.action.ts +++ b/apps/36-blocks/src/app/website/home/ngrx/actions/login.action.ts @@ -5,6 +5,13 @@ export const logInAction = createAction('[Auth] Log In Or Sign Up'); export const logInActionComplete = createAction('[Auth] Log In Or Sign Up Complete'); export const logInActionError = createAction('[Auth] Log In Or Sign Up Error', props<{ errors: string[] }>()); +export const emailLoginAction = createAction('[Auth] Email Login', props<{ email: string; password: string }>()); +export const emailLoginOnboardingPending = createAction( + '[Auth] Email Login Onboarding Pending', + props<{ pendingJwtToken: string }>() +); +export const emailLoginSuccess = createAction('[Auth] Email Login Success'); + export const authenticatedAction = createAction('[Auth] Authenticated', props<{ response: IFirebaseUserModel }>()); export const NotAuthenticatedAction = createAction('[Auth] Unauthenticated', props<{ response: any }>()); @@ -14,3 +21,5 @@ export const logoutActionComplete = createAction('[Logout] User LogOut Complete' export const logoutActionError = createAction('[Logout] User LogOut Error', props<{ errors: string[] }>()); export const getUserAction = createAction('[Auth] Get User'); + +export const googleOneTapCredential = createAction('[Auth] Google One Tap Credential', props<{ idToken: string }>()); diff --git a/apps/36-blocks/src/app/website/home/ngrx/actions/registration.action.ts b/apps/36-blocks/src/app/website/home/ngrx/actions/registration.action.ts index b28c9f45..dde52216 100644 --- a/apps/36-blocks/src/app/website/home/ngrx/actions/registration.action.ts +++ b/apps/36-blocks/src/app/website/home/ngrx/actions/registration.action.ts @@ -1,17 +1,8 @@ import { createAction, props } from '@ngrx/store'; export interface IRegistrationPayload { - user: { - email: string; - mobile: string; - fname: string; - lname: string; - username: string; - password: string; - }; - client: { - name: string; - }; + email: string; + password: string; } export const registrationSubmitAction = createAction( diff --git a/apps/36-blocks/src/app/website/home/ngrx/effects/login.effects.ts b/apps/36-blocks/src/app/website/home/ngrx/effects/login.effects.ts index a54c2909..6c979fb9 100755 --- a/apps/36-blocks/src/app/website/home/ngrx/effects/login.effects.ts +++ b/apps/36-blocks/src/app/website/home/ngrx/effects/login.effects.ts @@ -7,12 +7,16 @@ import { errorResolver } from '@proxy/models/root-models'; import { AuthService } from '@proxy/services/proxy/auth'; import * as logInActions from '../actions/login.action'; import { AngularFireAuth } from '@angular/fire/compat/auth'; +import { GoogleAuthProvider } from 'firebase/auth'; import { LoginService } from '@proxy/services/login'; +import { UsersService } from '@proxy/services/proxy/users'; @Injectable() export class LogInEffects { private platformId = inject(PLATFORM_ID); + private usersService = inject(UsersService); + constructor( private actions$: Actions, private authService: AuthService, @@ -20,6 +24,37 @@ export class LogInEffects { private afAuth: AngularFireAuth ) {} + emailLogin$ = createEffect(() => + this.actions$.pipe( + ofType(logInActions.emailLoginAction), + switchMap(({ email, password }) => + this.usersService.emailLogin(email, password).pipe( + map((response) => { + const isOnboardingPending = + response?.data?.is_onboarding_pending === true || response?.is_onboarding_pending === true; + const jwtToken = response?.data?.token || response?.token || ''; + if (isOnboardingPending && jwtToken) { + return logInActions.emailLoginOnboardingPending({ pendingJwtToken: jwtToken }); + } + if (jwtToken) { + this.authService.setTokenSync(jwtToken); + } + return logInActions.emailLoginSuccess(); + }), + catchError((error) => { + const errorBody = error?.error; + const resolvedMessage = + errorBody?.errors?.message || + errorBody?.data?.message || + errorBody?.message || + 'Login failed. Please check your credentials.'; + return of(logInActions.logInActionError({ errors: errorResolver(resolvedMessage) })); + }) + ) + ) + ) + ); + getUserAction$ = createEffect(() => this.actions$.pipe( ofType(logInActions.getUserAction), @@ -58,6 +93,21 @@ export class LogInEffects { ) ); + // TODO (pending): googleOneTap$ effect activates only when googleClientId is set in env-variables.ts + // Flow: GIS id_token → Firebase signInWithCredential → logInActionComplete → existing backend chain + googleOneTap$ = createEffect(() => + this.actions$.pipe( + ofType(logInActions.googleOneTapCredential), + switchMap(({ idToken }) => { + const firebaseCredential = GoogleAuthProvider.credential(idToken); + return from(this.afAuth.signInWithCredential(firebaseCredential)).pipe( + map(() => logInActions.logInActionComplete()), + catchError((error) => of(logInActions.logInActionError({ errors: errorResolver(error.message) }))) + ); + }) + ) + ); + googleLogin$ = createEffect(() => this.actions$.pipe( ofType(logInActions.logInAction), diff --git a/apps/36-blocks/src/app/website/home/ngrx/effects/registration.effects.ts b/apps/36-blocks/src/app/website/home/ngrx/effects/registration.effects.ts index abc68851..517bf992 100644 --- a/apps/36-blocks/src/app/website/home/ngrx/effects/registration.effects.ts +++ b/apps/36-blocks/src/app/website/home/ngrx/effects/registration.effects.ts @@ -18,7 +18,7 @@ export class RegistrationEffects { this.usersService.register(payload).pipe( map((response) => registrationActions.registrationSubmitComplete({ - registeredEmail: payload.user.email, + registeredEmail: payload.email, }) ), catchError((error) => { diff --git a/apps/36-blocks/src/app/website/layout/website-layout.component.html b/apps/36-blocks/src/app/website/layout/website-layout.component.html index 115f1284..3bb2f5b9 100644 --- a/apps/36-blocks/src/app/website/layout/website-layout.component.html +++ b/apps/36-blocks/src/app/website/layout/website-layout.component.html @@ -53,13 +53,13 @@ > Get started - + + + @if (getFieldError('password')) { + + } + + + + + + + +
+ +
+ or continue with +
+
+ + + @if (isGisAvailable) { + +
+
+ @if (googleLoginInProgress()) { +
+ + Signing in… +
+ } +
+ } @else { + + + } + + +

+ Don't have an account? + + Sign up free + +

+ + +

diff --git a/apps/36-blocks/src/app/website/login/login-page.component.scss b/apps/36-blocks/src/app/website/login/login-page.component.scss new file mode 100644 index 00000000..7f26ddcb --- /dev/null +++ b/apps/36-blocks/src/app/website/login/login-page.component.scss @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/apps/36-blocks/src/app/website/login/login-page.component.ts b/apps/36-blocks/src/app/website/login/login-page.component.ts new file mode 100644 index 00000000..b31472b5 --- /dev/null +++ b/apps/36-blocks/src/app/website/login/login-page.component.ts @@ -0,0 +1,139 @@ +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + ElementRef, + ViewChild, + inject, + OnDestroy, + OnInit, +} from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { Actions, ofType } from '@ngrx/effects'; +import { signal } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { Router } from '@angular/router'; +import * as logInActions from '../home/ngrx/actions/login.action'; +import { GoogleOneTapService } from './google-one-tap.service'; + +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'proxy-login-page', + imports: [ReactiveFormsModule, RouterModule], + templateUrl: './login-page.component.html', + styleUrl: './login-page.component.scss', +}) +export class LoginPageComponent implements OnInit, AfterViewInit, OnDestroy { + private readonly store = inject(Store); + private readonly actions$ = inject(Actions); + private readonly router = inject(Router); + private readonly googleOneTapService = inject(GoogleOneTapService); + private readonly destroy$ = new Subject(); + + @ViewChild('googleButtonContainer') private readonly googleButtonContainer!: ElementRef; + + public readonly loginInProgress = signal(false); + public readonly googleLoginInProgress = signal(false); + public readonly loginErrors = signal([]); + public passwordVisible = false; + + public readonly loginFormGroup = new FormGroup({ + email: new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.email] }), + password: new FormControl('', { nonNullable: true, validators: [Validators.required] }), + }); + + public ngOnInit(): void { + // GIS script is lazy-loaded here — only fetched when the user visits /login, not on every page + // TODO (pending): GIS One Tap initialization — active only when googleClientId is set in env-variables.ts + // When active: intercepts Google credential here instead of going through Firebase popup + this.googleOneTapService.loadScript().then(() => { + this.googleOneTapService.initialize((credentialResponse) => { + this.googleLoginInProgress.set(true); + this.loginErrors.set([]); + this.store.dispatch(logInActions.googleOneTapCredential({ idToken: credentialResponse.credential })); + }); + }); + + this.actions$ + .pipe(ofType(logInActions.emailLoginOnboardingPending), takeUntil(this.destroy$)) + .subscribe(({ pendingJwtToken }) => { + this.loginInProgress.set(false); + this.router.navigate(['/onboarding'], { queryParams: { token: pendingJwtToken } }); + }); + + this.actions$.pipe(ofType(logInActions.emailLoginSuccess), takeUntil(this.destroy$)).subscribe(() => { + this.loginInProgress.set(false); + this.store.dispatch(logInActions.getUserAction()); + }); + + this.actions$.pipe(ofType(logInActions.logInActionComplete), takeUntil(this.destroy$)).subscribe(() => { + this.googleLoginInProgress.set(false); + }); + + this.actions$.pipe(ofType(logInActions.logInActionError), takeUntil(this.destroy$)).subscribe(({ errors }) => { + this.loginInProgress.set(false); + this.googleLoginInProgress.set(false); + this.loginErrors.set(errors); + }); + } + + public ngAfterViewInit(): void { + // TODO (pending): GIS rendered button — shows personalized "Continue as user@gmail.com" + // Only renders when googleClientId is set in env-variables.ts; falls back to manual button below + if (this.googleButtonContainer?.nativeElement) { + this.googleOneTapService.renderButton(this.googleButtonContainer.nativeElement); + } + this.googleOneTapService.prompt(); + } + + public ngOnDestroy(): void { + this.googleOneTapService.cancel(); + this.destroy$.next(); + this.destroy$.complete(); + } + + public togglePasswordVisibility(): void { + this.passwordVisible = !this.passwordVisible; + } + + public getFieldError(fieldName: string): string | null { + const control = this.loginFormGroup.get(fieldName); + if (!control || !control.invalid || !control.touched) { + return null; + } + if (control.errors?.['required']) { + return 'This field is required.'; + } + if (control.errors?.['email']) { + return 'Please enter a valid email address.'; + } + return 'Invalid value.'; + } + + public submitLogin(): void { + if (this.loginFormGroup.invalid) { + this.loginFormGroup.markAllAsTouched(); + return; + } + this.loginErrors.set([]); + this.loginInProgress.set(true); + const formValue = this.loginFormGroup.getRawValue(); + this.store.dispatch(logInActions.emailLoginAction({ email: formValue.email, password: formValue.password })); + } + + public loginWithGoogle(): void { + this.loginErrors.set([]); + this.googleLoginInProgress.set(true); + this.store.dispatch(logInActions.logInAction()); + } + + // TODO (pending): Switch Google button to GIS rendered version once googleClientId is configured + // When true: shows native Google button with personalized email ("Continue as user@gmail.com") + // When false: falls back to standard Firebase popup login button + public get isGisAvailable(): boolean { + return this.googleOneTapService.isAvailable(); + } +} diff --git a/apps/36-blocks/src/app/website/register/register-page.component.html b/apps/36-blocks/src/app/website/register/register-page.component.html index 1410c576..a34d5eea 100644 --- a/apps/36-blocks/src/app/website/register/register-page.component.html +++ b/apps/36-blocks/src/app/website/register/register-page.component.html @@ -1,7 +1,4 @@ -
+
@@ -76,58 +73,6 @@

Check your inbox!

} - -
- -
- - - @if (getFieldError('firstName')) { - - } -
- - -
- - - @if (getFieldError('lastName')) { - - } -
-
-
- -
- -
- - - @if (getFieldError('mobile')) { - - } -
- - -
- - - @if (getFieldError('username')) { - - } -
-
-
- -
- - - @if (getFieldError('organizationName')) { - - } -
- +

} diff --git a/apps/36-blocks/src/app/website/register/register-page.component.ts b/apps/36-blocks/src/app/website/register/register-page.component.ts index 64879448..10a804ce 100644 --- a/apps/36-blocks/src/app/website/register/register-page.component.ts +++ b/apps/36-blocks/src/app/website/register/register-page.component.ts @@ -3,7 +3,6 @@ import { RouterModule } from '@angular/router'; import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { toSignal } from '@angular/core/rxjs-interop'; -import * as logInActions from '../home/ngrx/actions/login.action'; import * as registrationActions from '../home/ngrx/actions/registration.action'; import { selectRegistrationInProgress, @@ -36,31 +35,11 @@ export class RegisterPageComponent implements OnInit, OnDestroy { }); public readonly registrationFormGroup = new FormGroup({ - firstName: new FormControl('', { - nonNullable: true, - validators: [Validators.required, Validators.minLength(2)], - }), - lastName: new FormControl('', { - nonNullable: true, - validators: [Validators.required, Validators.minLength(2)], - }), email: new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.email] }), - mobile: new FormControl('', { - nonNullable: true, - validators: [Validators.required, Validators.pattern(/^\d{10,15}$/)], - }), - username: new FormControl('', { - nonNullable: true, - validators: [Validators.required, Validators.minLength(3), Validators.pattern(/^[a-zA-Z0-9]+$/)], - }), password: new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.minLength(8)], }), - organizationName: new FormControl('', { - nonNullable: true, - validators: [Validators.required, Validators.minLength(2)], - }), }); public passwordVisible = false; @@ -92,21 +71,9 @@ export class RegisterPageComponent implements OnInit, OnDestroy { const requiredLength = control.errors['minlength'].requiredLength; return `Must be at least ${requiredLength} characters.`; } - if (control.errors?.['pattern']) { - if (fieldName === 'mobile') { - return 'Please enter a valid mobile number (10–15 digits).'; - } - if (fieldName === 'username') { - return 'Only letters and numbers are allowed.'; - } - } return 'Invalid value.'; } - public login(): void { - this.store.dispatch(logInActions.logInAction()); - } - public submitRegistration(): void { if (this.registrationFormGroup.invalid) { this.registrationFormGroup.markAllAsTouched(); @@ -116,17 +83,8 @@ export class RegisterPageComponent implements OnInit, OnDestroy { this.store.dispatch( registrationActions.registrationSubmitAction({ payload: { - user: { - fname: formValue.firstName, - lname: formValue.lastName, - email: formValue.email, - mobile: formValue.mobile, - username: formValue.username, - password: formValue.password, - }, - client: { - name: formValue.organizationName, - }, + email: formValue.email, + password: formValue.password, }, }) ); diff --git a/apps/36-blocks/src/app/website/website.routes.ts b/apps/36-blocks/src/app/website/website.routes.ts index 41486725..77e5f6af 100644 --- a/apps/36-blocks/src/app/website/website.routes.ts +++ b/apps/36-blocks/src/app/website/website.routes.ts @@ -40,6 +40,10 @@ export const websiteRoutes: Route[] = [ path: 'register', loadComponent: () => import('./register/register-page.component').then((c) => c.RegisterPageComponent), }, + { + path: 'login', + loadComponent: () => import('./login/login-page.component').then((c) => c.LoginPageComponent), + }, ], }, ]; diff --git a/apps/36-blocks/src/assets/images/flags/ad.png b/apps/36-blocks/src/assets/images/flags/ad.png new file mode 100644 index 0000000000000000000000000000000000000000..fd1e745327301d119e9ff92ed6953cb254fd826b GIT binary patch literal 600 zcmV-e0;m0nP)-^RENHmuUX!V)VC> z|L%kEl?I@{xL5!H0ij7mK~z}7?bgeZ+aM4HP$kao2Q&!K+mdJEvFHDPF`Ka$shTW= zS1I*^<*B})7BoM;t6$AO>h$xwY7X!K5AXo@gZ{a^26R-!1#+(dMWSyqKm;v~L??A% zR0fF0$MPvy!<1#iMAMFDqvmm>{kmmFkXfOo76Z9Y>Oxyi_o1PsK zw3oeLAOel!Z5+q(0Wvtq?mg@iVVcHioaWr+EpM5$W)GV%gNJS#x-G|;opX^mg_=pp zhTrGY(4C?irnc?GtW-@(Bzk~NcRqg#C{|30?~$Gzy7Kn6h*2N>ZZOZr`i$IO+D-^G z$C?g_hcD27p3j2=q2J%3Q%iIBI%OB*QbL-+Za>IMY(zu^5P`@Nty~dVv1&@ds^Arr zX3~}WiVs@?tFi(hHfE?Q*wy@CC6^KcpzEqkeF!B>^)>3fBM_Jt?_YH<8ztu1z3%0( mlu$}MUS9`zfCu@l|Nj#LdaJMP zU$tu0#F-C3N_9P5978NlCmXaeJML*n40-4g@}fyxK{MnKx0@)Rdh5ap#z{_We-c6- bb_8-T?0>pC^!-ICF_3Ydu6{1-oD!Mn0002qS4`VUJ=QQH>zI(`cWvp7gx_3I>XC`vQAOv2 zc}H9-NDBt$est)Ee(a!`^TE6CtE6_gl8udw|Ni^&w5@-Cek+k!oSm91EG&b+oM|{T zVy%LY#HJM$752}`n#!&gg-3I9azjHyLY->(+t*=pNUYJh{OaamVPI3GcT!SPj+=Y3 ztg5cJpoLvob%kH9laFX|~B)L%X4}e-Kr8rHw$YQ~jH~$wXm6zTT0g>t$kUX&1k=sEd;>-vGKx%*8t`yf1H`EfE7 zobLKhZUBHp0H8Ghq!IuOf8A7*Vc@Fk>mM8dkZ}#236pY&1;A^7K-Fy!`@UC5UkN1wJp9=f}nO!D%<$cl{g?K}(i##sC0DBq@kf zz-co(OlFgBgZp|lo_2Ep)E}MtcQHu;oT|xaJ3D+E{HQO}@pKN@mPE&*EsCTp3R|>o z%SoF9r^#rtST4Q|KGj{fAJ4(p4>BrjlsIn;Ekcx7As^Nbr_rIR&W8a#+;#i?J=W`n zMFo%IYZNU{so>3Vjl0J~RSoFjW!HCgeUEi>EX&e6O^5;Dk1W>ZLsQ^xxvZA60bB07 zzV7GYp*beDRXomZ1i&AaqRFvY)6;pmsWy)TQvP`9Ki+K9P-#o8L>f^pVH%;SrVma2 zzSx|r0Vz+XPnSzK_ss)AUQi}D2}K0bD4N4OH0ph}SUgU?-^0~vJRXndC>n{V$ed8b zG3!ag(*V;HIE_Z5(RTZNu)FN`yHC$rfUaGj?K&4(!W!y0&{F?gEvjlZ0KB|(ef^n9 z0B)V+HqULTm~E1T1CZJC@;o~)z7LM4yRQ5BBM|^-0nI5>G^MP$4iGwe{W+@^lL23w z>C?-ue@m6|hI86jO>S&Uva7_s}*!FE^Xz z5OBQj>-r_lJcRn+l0IZVm$S`b*sb@}cb_E(Vreu0%D4w0jEn(Z_OtWjz-x3>@8<-X zxzcK7V2m*^O6PgR1jzegHu$1njqgQL>X36t*TMd1~{dAt%^cdwKa)Emm^Eiay@@Spe^nG%;WmwWavBA2G zxszi)3D=jH@F1n1xt0YD7XaA}rukkd``;XHCIW=AJDr64BerS|cf z#mq%Ff^h&Ck&JqsrjblzE|)cZ}~Csm4-C5u&Drb&|JvEr;OnNsxm#u-~mK*q6( oH2~;X@mK;<{{7ec3;tp7A80N$q*&}`uflvG03J6_RJL$4*^&P z58=8KZ(Ip~X$o9S2l2YV_~7E#K2Ns}A(D9vCm{pccZLvYxxE-NoG45)Dg@ZG65?@w zUlk-O0|!Vv2JOTY?yt7iI7zV%ARz(aOg((G#TS2NgRuf>g3vOh3bsU zs9w{wUZbTd;641H%ILFQx3 z_>_zF0o#lV*(3pCP<{Ii^}vMRR0ou0bf!3^p+o=rQYWPR zMyU%Z%Sa-IQdmT^0p%GpPv-M7lYkw6V_Y5Us#yC6c4Z`GNWFhkGmnNPF$pM`p9x;y z-!2rqy}z~x=b&MC*^8ad2agYZd=HOWAryUt1sL#Y?%RM7#u>L}KI4og0efXEz?hB2 zfP$^PfTkJE0~%&5peOmclDx0ah2%;>0{xlnyM6n~03qCsyL{t27)0JB%wZsjy@0BW zx0As_X~v-eJ2U2R5{bQlZN^)B0c9Ca3n-W!3TI$}gN#o$d|&trQ5+l(KE2fqNJ<54A#J&w-+0000F~ z5HA1!{{SFq)=XkSS&x~_|MA1h4lHqikhBUZZgYgJR%@I8nE+00r2pi*|NHcLimG6+5f_4q|f_GVU^TETD`^DjGMgXxWoUYAfCePJywlseW>2x=kwp>vb@pk z$k7b+5yb!i0i#JoK~zY`?bX?Gf-n>Y;CM=v#h6%8kfjQUOSNuo-~ZKmAjkwnhYB~H z@xO2&%Qtay5{S|R7!6f&Ngp~G=;sZpHdi`IkJL>vSSCxLI-H9UwL$H(NEX0sb=Ygv z260k>lt78o$zM_+bMRrVM9u^_dzgC_**HH_Wx52g1o$Q1Ce9`sP#c7+q~KL*gPofB zU*J*fQ(qLTeryby)>hMYXMpog)3%n`cvH-z!DE*$v$AYV3t*YnN(yFg^UAVG!GO{g z^MWfdE9?nCPwBjmjZ0w?r^$v^lpP(m>uo|T;j0UX~|sa`qGV@l;@myu!22OE~P%ethCEAcXh$)Mz(%=&IUOC z-vqSxH0H%~UgRo10of|$IST;aw*znG^EhO7L>k8ek5U@?+zuH`ntNmm96{e^G4Aqr z3!nyWa!zcv!rxO1V01Zk$XaR(ATi(aIBj@j(alrd+OUTm<>4gdfE07*qoM6N<$g172I!~g&Q literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/al.png b/apps/36-blocks/src/assets/images/flags/al.png new file mode 100644 index 0000000000000000000000000000000000000000..468caf5272934d17afeb4314722b3c3004dabbec GIT binary patch literal 643 zcmV-}0(||6P)hULLj5&&o$FU)8P0I4L7JC=1Gysb0uSvJ|tf8xAt zv3+CoO2qbe0)0o^XqyD!jCa6s0JQ50TZ!>rVU5ymTn;NAZ2ig8jg!~)%b^3((mREz z32{r!Hcf8++c~-eZ>k7l5jkS;yJ`~X5$YiN(3cE9U?PXhmLIH#Y z(3jm*?f|h#@&K7sK*g{CVS)A~ML0pNkS!iNH$iowX91OhkstgUj SY32bnFnGH9xvX0@?kEP)Um;ixh0P1-Y_P+tNj{vKP0MHmKpnm}7YZgB;0L%$4*f%5IOCHXn0BKYJ znR)>3h!0FW0Pv9wek2of6&06554C!2fdBvjU`a$lR9M69l*w*`Fcd|f!S?F~Y-Yk3 zGNth09KSHgUnR(Ve5{8r3fYwvU94ocoIVYS`3CMI_ zu8;PxsI8l*Z|-lofjC)HyZN>X#x5OXCnd*Y<#>Pr0EoV- zI)SzkkN4+~5rMu|xDk+*qRQNiSw&=lJh(svL`m14a`%dDQxYx7@=?_Z`6TJYA@FLX oqcpi+W7Z14LJGFDva;gD2R6b;@Y?!2-2eap07*qoM6N<$f{$YAF#rGn literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/aq.png b/apps/36-blocks/src/assets/images/flags/aq.png new file mode 100644 index 0000000000000000000000000000000000000000..5041c1f89c77f126eef727e014a99c480c75fad8 GIT binary patch literal 481 zcmV<70UrK|P)U%_{_P90%Y}qgI=2eQGugW!kJ(E+dX>Ymzv)csWuVa^SKgk;}TtY1e-s zZ&xo@C8fm4lH?|(Ty43tGs*7n_ci0{dGJpi;crf^o@P!EE;d54-9e}#D_SyH1nY9? zaR+S#F-rV)>LAD>zuoL_<9CM3AMsUars0dQTAK~kqYY1#)l3Jf;vGCmRx=$ajQO?~ zRHRuW4^@&)4!#swBL`K)n=qYlo6usA9{MtlCgT zDY=CvvPhj-fbN*ORtS2i%R#U~-53NZ>dKHTxKs=|5M@T$KC#CiIsBqw^DWW)x>uyn zT0#(`w}U<_k6`umts_K|zFUNtr6-<8u(}IYSnCMUNYAx_Fy|jMr`8;VOU%vLHvXGW X;WK8PX<9O000000NkvXXu0mjf;j`Jn literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ar.png b/apps/36-blocks/src/assets/images/flags/ar.png new file mode 100644 index 0000000000000000000000000000000000000000..75f031cb18511880e6c877da97be8334d31a29f2 GIT binary patch literal 335 zcmV-V0kHmwP)&50M=K~zY`?UjoS!ypU=F*a_?pO8S< zf6+GW3YMZuz5z~tdN!DcFh+$cRG|w0RQM9c+=6w(`{AsVZzli*M%snuW8hL-0ALZL z1*q-l{b-d)BDG^IJ*E_AMRo#0;;_YYtut(=L43(Ky&MWmYL?VwX za?V#|B$-mSd6m)|iIif1>T&e>SsO31Hf9fqq1C{Hg^te>G9iG}>3y5_&bxbFCi4_V he?1kdP=zY|@dirmQn3=DVmkl;002ovPDHLkV1h^WqDKG# literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/as.png b/apps/36-blocks/src/assets/images/flags/as.png new file mode 100644 index 0000000000000000000000000000000000000000..78cb337aab7843c716aa8a9b3ded3f97ee11de4c GIT binary patch literal 752 zcmVrwNC=%Oyg~~fg>a)1|`uTM^7;#e-y}P@IW*66Ncd39J=H=y5H5_bNOPrUF z_~qwWMmeO4M(^(J$;ifzcuSge8i90fVM7(dl^)mD*2%k;+<}Ukhj+22i-bTLgMD?i zqHo;OyUM|@<+3cdm_~v_A&o^I-Gq(qtGOTm00Hz#L_t(Y$IaH+a?>yv1>hr@C4f*R zs0y}hyy1Oo_7-^m=i;VKLTxv;X`Om@o8P|t5Z{J}~Y_V7@FekS7{No05 zVm|?3R_qe66PpTlVfJ!qP6ChE?ajx-vGyes%o`1MV}OzUURzc)?#c)3+wJ#L3}&+Y zWmy*Uz2RUl1|)^B))recD(zw5D;QuDN)d}Oi*jbk^WYJ?YhwUHL5Z&@W1OpXAk#$F z{oph9sRsjKGe#)ooO8h$3#4b*VK;cdzTSN?(7U8kicl^%A(RLe$uP9r;6Uu@##~WB zh$58G!e~Fk5f}gjzAuOnL=Z|M@8z#|#O{Y+0N`!HBBGp9N_df;f)g+Ru)S19zE6Cg zD;hoT9gQk(%kA+9F`^#1?VP)tH zprE{`i(`nz>Er|n)-CL-H!!pX=p=+pIMo#4Tqkltj)B4YNO!5^-NmUur3{{~elF{r G5}E)Bdmu0X literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/au.png b/apps/36-blocks/src/assets/images/flags/au.png new file mode 100644 index 0000000000000000000000000000000000000000..95767e74087bba61467b63e586636232edb9370c GIT binary patch literal 592 zcmV-W0vj`||4lHp&S&vm~n*kwd|NsB%Kw$X4$?d$!Dn)^SkhFG(t}{)CN@11v`1_-; z$sRj;*W2g2!`JX|h>xAU0wQYb*fF@kbk%16GkSz(G+$52? z2n-^L%mJ#oAISA>ToDXRrVVqIJ0M@b1_K2zcE}BI#TDGQ_kQ;R#U8l;uW&-7=?QR$ ze2l=yC5}~XTQL`yj$x}$C%YF=j=*7htL(JEZTJcFZqo!#5JEgzXQ$GDRxU6!+@9;C zs6|X56M{trp6D<-@Yk2J6(sk`rUYJ{?1m9Iy?xGQv${wB?h8lQ6v!o!w^i74<|u4; z;40v87`+9z8$BPAahvk}<=PhITW!r@gFBdm2iXood#KRpO@A6Nw( zC%6`yn#s00pTW*m&I4!5GF9JXv&VUV0TjsPQjWFtcZ2;~7!wz$C{=MQd_E($9CU_C zMFtj0L|~dR(KLc(X(S+P=o_eL!(z3Zj`nAwogr@kpy82#ETLnCRA2YZ*d_3;bl(C% z+v}^QnaZqU0kSbDON1!#NogOV!wlAL%;tQI8=x@(K%EJZ>1!Y}!(c*Mu9wI6xYx$i e@%`{0D8vsZIx?9BZDcA0IsUwQjcxhw*PgKA(A1I;UL5Non(k)h-5g(ux&5!0SN9E Utj(_g`Tzg`07*qoM6N<$f(h7p82|tP literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ax.png b/apps/36-blocks/src/assets/images/flags/ax.png new file mode 100644 index 0000000000000000000000000000000000000000..0a6b0b1f5e2fb4cc5bfa54c8b8cdf2f04367e8dd GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfR!VDzeM=iPpq@)9ULR@e0iT=OLz>u=`;0`UO z)U}VS1U|NNB=u$eyTlmaG(Q%o%)`^gF~s9|azT(&gOg(*8=IMLk6n~LLN>C z$>?F>S;*D9k)h4aF@+(pgVlp)$)SmyZBAzd=AM}#wC+?!nQW-V8xbakHmQ4}OZNSX Q0Gi3*>FVdQ&MBb@0DQeS9smFU literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/az.png b/apps/36-blocks/src/assets/images/flags/az.png new file mode 100644 index 0000000000000000000000000000000000000000..d43251839501832d686c1352201ae04febbdaec7 GIT binary patch literal 262 zcmV+h0r~!kP)Nv_ zSm3+zBvp>jQjD?`h|20r`iDMr9A4uz+O7O{dJl4NCnv!K6TAla1nb2_D+mP~*Z=?k M07*qoM6N<$f`F@Y!~g&Q literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ba.png b/apps/36-blocks/src/assets/images/flags/ba.png new file mode 100644 index 0000000000000000000000000000000000000000..4c3360317cf6920625ea5fb81642a6a5db8ddff6 GIT binary patch literal 346 zcmV-g0j2(lP)p!Q(9#D$N~~Foc_xIFhY5NlFHNB?MY&@9Xz1|B$bn)(v+gojhxVbkjgI) znneHr0N+VOK~zY`t zsF6W~unZhTW$+*<0|!wVd?6^K3L-MPARwa*wq?%-X#3X sgQv`T%5+$mWsWR!WSKs}i;NKb0LjN4{5i;^)Bpeg07*qoM6N<$g1Fg|H2?qr literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/bb.png b/apps/36-blocks/src/assets/images/flags/bb.png new file mode 100644 index 0000000000000000000000000000000000000000..71fe685cd0058a675226728b06dffc8b9e5497e0 GIT binary patch literal 349 zcmV-j0iyniP)`uua}ohn0GRbK(OV`wi|i zHy9vXV7dCm)p{HG0^3Zv6O7me+RU*NG@^!qjcL2V#=Zf-w$JKzf|);YJOGv+TQRWG vVlPiUuvaf@f&UmxrKI&)THpc~=m38K757yB(y3YyfvE%0h zuNt&CXPlJL;9y*U=A>C$&0Qm_A5EbgT)G>34EXX?5E1Hcill zk=$~8ruYtdxMRrxL-QdomiS`S`15yRul(JFOClR@If!fD;20jnn{?Ykk(n!?0j YbVy_BtRq^df$nGUboFyt=akR{0Dzoa$N&HU literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/be.png b/apps/36-blocks/src/assets/images/flags/be.png new file mode 100644 index 0000000000000000000000000000000000000000..f6c419809f84885cdc5a284e7427cefdfdb0aac8 GIT binary patch literal 127 zcmeAS@N?(olHy`uVBq!ia0vp^0YL1^!VDz!Rcf{YDgFST5LY1m-q_*qE!EH2W}#j@ z-}GA^0fn?ZT^vI^j=w!+D9E6|!?Iy}0QUoy|BE8xo%Lr<-co*Qu2`UmD+tAi*|)7Y Va`?xs>Apa144$rjF6*2UngAj{Cg%VE literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/bf.png b/apps/36-blocks/src/assets/images/flags/bf.png new file mode 100644 index 0000000000000000000000000000000000000000..7034f790b6659c3b1209e26b5affe87409d6959f GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*mlx~1ei0gZ8U50s{70FhAE{c8* zSN(HL?8hY8%O_>!mpJ;ZGw<4^)4Egly^UtwcHJ{8l--Q}SO7J)d%8G=cpOhokYHV$ zu!K>JT}gD4s=&$#rVSpg=hR%Ze9V-c1pB+Yy*Fr1uyF85U1caCU^YcnV#zrXX1BA!DcNHYO$)ILYswQn|k!C8&B`w0y>Go)78&qol`;+02xeISpWb4 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/bg.png b/apps/36-blocks/src/assets/images/flags/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..25808e0f7003a0175f1b4a51c90a543add877f30 GIT binary patch literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfP#0(^VcZ;R~Db4_&5Z7yJLJZUL{{R2KPTl!B zP*B>_#W6(Vd~!r9t3eOfBwdLvRv@Ks!L@>mVKtlGg>-ond!RA~Pgg&ebxsLQ021UI AH~;_u literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/bh.png b/apps/36-blocks/src/assets/images/flags/bh.png new file mode 100644 index 0000000000000000000000000000000000000000..aaa1238086d8f65b32f8dd7b7f5511cf8ec7f2d8 GIT binary patch literal 329 zcmV-P0k-~$P)I$HeT7hwq-4=WuA_UR3IW zdhM2vtrVM7bXpq}{U{*&WOyhr zZE#}a(!-a-_u-9J3cO%@SO9ENtc}7(Pe&0xEYWd}51c(Bafi_U88@mF`0!y*Gx&J? b=e)fD3OY%m=!`H;`}@hw zuD#>6+-7;OH8Zl8cJBD==kDJ0&D56Dh^=#5s5~+2s5-qz%N8It)^2g5h+1=`=va_&>vaN>1xtz>TAkqK;0kla(K~zY`t(Rw$f-n$3 zqm%?e6r_lN72DnU|Nq`8=tvr6ll{an!y6uKwjfl;+{B7u&Ji6y6BXQKiMW^vh`fj00{wlQ??7IMm0c? zH)l%$$9wa(G_cG2U`B=!nTH-*7AW(M_Ca$i*hihVJW%9qX6@sYnH{zQ;M03Sd+!3~ zgzn_FLLlRP`&>O9pR1eHRsy8Gn~xVJmrD||<;2>!WC)P)e#JV*I9@Y1Ia@i9_HKYa z0~FYH0U2*jS!mk{WWB?%-?j%x93%}nuM2pT1CJo!Mh@J7fLl3ms{*XjR{B&bK=1Wv zdd(C2ok5nJND~^?8T%_Q%X%bufhO6<3 z{W*Hqt_}9)tdjyV~YbWiT^Ed|`I7{)sse2^WJhZE?6(zk^v~2It#pf>EqjarinwH0s d!RcFX{{c}+Tge+Kfgb<>002ovPDHLkV1ioNJ<gQak}ZA+8MVfiDDg|6CONSg3fu zr%VATuH@bP0l+XkKg$E$Q literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/bm.png b/apps/36-blocks/src/assets/images/flags/bm.png new file mode 100644 index 0000000000000000000000000000000000000000..09a0760e71d7bc376688b445df6e62a6d67bca4c GIT binary patch literal 971 zcmV;+12p`JP)iJ4lDNd_y7O@0U>Gs{{Has_QQ06yFOAck0E@FvVV`WEr=i3QfSy( zZ`Mm;`TF~1vdz;yR^#RD)I(eI$IgI|w6_u|_0reH4lL%t%BedwlP-KBuRFI@Sdm@!} zbB~I5z8p7`u8>-!P}jj?xP~fwRz$f!aO;tyEQkZ-| zbfTEbu}Pz;ZxAkWx534tuv&zhf?`h}zrdWcs;B1d+*$wt0$@o*K~zY`?bX?GqCgY| zU?u`B&VVQ+sKfvo_az$lEpdta?qr{2miK>&X#|}BUTC!!bCLgwLhGwj-G_59&I^Ep z!R?!zP#6q2*}lM;3l8JF*uLQ~mw_~akaJ<4O91u;8QFum&LQchXvcjy zom^M>0mPj)o%7-L{Xx4*o?&jC+=7sEV`o>J+7AI$GPEJDHSpTV9RPmOa+?XcxHtfS z)IdJYxgbYoZnfXP?+pTTsGV>3zvaW@k9;-dK8yqsHfo)e+)8LqAZ3F)YJ14ZGZFDd`5Ji84vVeMHI{A8e0V^3M52~Xtv;$Siv8V0~%-e^fc0wGktmx)`a({NBpmqr>Zto3`t=VGx~>*t?&Bj|%?cL~SM1+!~>F&fFqj1gSahUL?{({*_B zEq~;!16Hll3rDsAB+IYkr{J9`)?SlF&}-m!tpJ@goS{5_smy+67H^BRoIr1E%1umO z(v^N`S`sG2fJ6opVR1g5Ri-yLjrvR?WMnX;%maboQv-s3grE{Zudo^vgn-a%ya~J` zShXR8Bo+7_AccCJOa)TGRMLS64wK2`dpez>C}CWAUyeqjHrmAQESKGtGAZ*yJuR+& z(R5Tq+W}IPohnL~EtX^KN@;iL66#iIN7>FJO|vXb#~x#B){nfWq!_fcu+h>{HlLJ@ t!2;Q6Cr=z}n-Wqsn-~4qXFl^E<}cohQ%kt3bQAyp002ovPDHLkV1n?J&?Nu> literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/bn.png b/apps/36-blocks/src/assets/images/flags/bn.png new file mode 100644 index 0000000000000000000000000000000000000000..32456aba5b0928e54bd7bbd86a2cd5fcc5b29432 GIT binary patch literal 995 zcmV<9104K`P)}v1m=joOk zLIex)xxd*$Qg>_$`|o}G@QZqRb*QJKL_0WcYHIGW8RU6=+e%l{DI#hI5!*^2-Be>Z zGXzRQ1}!WqihT_8+!mmb4&2<_{rS^PO-=sv_U4wrVx;jkf&@C^wJmJVsF#a)4smG#Kgp*P!+o;9nkI)T>t?wOS97rry|^rj56zZIaeAJ(9F(zyF8mvJl58AZhmbN5&a`!@kP{ zfC%9L;^01MkbklJYUdeA5a&5D)dd}O?{J4GXeat%@8v#8&{224|F`N1;ym1}S?J5KkveT)oPUw)d7IQHcRKfq5)hh(H^y9?Uvht z!ypyhhb@*~zxU*#2@XO@g0P>6Ztnniko4)%m+bm#xdsApOm4ch17I`p)2rXAy-@eO z0wT}t=z3^9RNOQrq0`ygndeZS0^#GQB|iCbh-9FiAur01HeBlGeBb< zIVZ0fDS0CDDwqWdsLojP_5jD0B(gfg=z>@?(8B9@o7@hhuI|(@pflDVf5xH!l55XwDRGmLJpZ_zY_6bphA3|^FT8l-F1P}XSLkfC-xjz0;+t1f49Jn>U&LqRKiWxy{{W#>hbUd1 R0!jb?002ovPDHLkV1lg9+?4JP)A0=A>!Cd%*HchmuA9P8q7PtvVa2F$$i}?T|8Fs#_x41gG zvSieFe`*>?gBsMJ1~vF1uvIDJR@I=#X@WNg)HGwOO1VM@^+(B%H@b|><}*MOum{WE zW8|IW_E6%dm zGE2wVa1$#nWDX<54vy#ZF|Y+;4g;k(Bt__8GRXRegO?6`?1Y6HSTgF8Sx?rxT}$?6 z#HFlM0^0`VBE83x;1(@X-`i7aD1JR|P}jFttHB^!3E!m#R|IiLr|$4B(^TGv?v#dD6%?Iq zG8Fk_l8a%o?Fdy65gXYAk;#PM|ML-8uNKRySVV6hPfbmO8q}Z$HTWX%59UL6Zn&B* QYybcN07*qoM6N<$g4IJ9g#Z8m literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/bq.png b/apps/36-blocks/src/assets/images/flags/bq.png new file mode 100644 index 0000000000000000000000000000000000000000..fc7ef2d29d6d142f9fb9d9994ab49a4e3b7cbd85 GIT binary patch literal 886 zcmV-+1Bv{JP)vTC*6rC00076NklJJ5P;!P2B$;;NhE<K_$mL=Vf;}!k16xw+<5H)*+j_xs>7Hp-P}IuT&?>1SRu+R4E(Gk(UML z%F6)r_^y2Xm*}d1+vnH}nqmYCnlG!Pcd&RhHI^Kb{s3$oqOi znc(>?bUhT)pX;)DyI||OxJ2~rLDLQ9?LK;%WL^?vd4)E1R_onk7hSo$1lYO;SX%b> z$^{*>CY84ZvOIt}wxh2X{s|Gi^sQ;8=WRfq2Sw9#qwl{ruA&b%4pTUNUtSD`c|33$ z{lnjx;fPeP^Kq-2--t57FprJbV=raLd7l`@%yFDMc3Hu$L|zDrJhrRh3SKpsHZ%Be zu#2`t9tYz*9y8}}cZQe=zu6-8^uzNwxSqvJw1lS<0hYr*_prA)-r6U539#nl0K`47 z?-;~e|~iM%8TZzc!Ji;TFtWrcex8U^;-e;$w*%_6en&jaPw}HXmde{L zgcX{Dt)H_I`Z{R$M7cp2TG%edpZhp+3l~JkfDrW1@)niV_{~Ji)+O^&K+p$%^c!W` zCF#60kUxZhZw89anm7H*0lbwdHZ6qo#{@Dc zfj%^cO+9W*M3IWJ9l5&^$G#3Po-@|M3T9uTMK^P-h%;bKVqRCAyW-4>ZAjRx7<_fE zRYYl>ySvxy;i#s{rP{p7pCOEfx3sm;$miCXwHkV^B9)N6mC~?QP?-4q`dU(&wAaXa ze5z@{j?mrS%*ViurLKI6tEI`nqmYDvc9zwxFK%e0&$xbpA$%zBZ#|!eDkT2t8WUf)hZ7;+y z-3!xqUMxbXr(?55nY2BEj0h*H;RlBr6Eg?mhR;A!v~5=KCUQg`b4b`%m?HR;Ni#v+X}b-u1i9?% zxWQr!-xzDmU{SAq;Rw)HFfogafV?3^n_?Knh7=p4XqFzMVZE~W{|9~ft4IaQQu*s# u1q){dD{=Wtdj-#m@*h4GJk757(fA9CHY~S?JH*xi0000?5A)~hjuCNp@47bnU2+VFnbqj_MO;@m3f?fvrBC)Vcx_0IQn zaSZV|zIVDeU$cS0QJE6~r`GF!x6cU=Wjx4~^pH8?l=7K90pa|j3aODEJevew#fdeE zJ@xnS2>f)sbCT+@osq$HdE0m*#f0|i==4mAj`hKxW%6qZC~9HGi_4z^CyQg g!;^MyxqZG%f0?7lsUzFgq=NkE>FVdQ&MBb@0K%PXOaK4? literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/bt.png b/apps/36-blocks/src/assets/images/flags/bt.png new file mode 100644 index 0000000000000000000000000000000000000000..3c26d439839c1ca73c62569e50ba944fd17c4518 GIT binary patch literal 1086 zcmV-E1i|}>P)u zOzh_3^Xts;-=Fr;JMzb}@8h@jc|GyZ!1a}A_0(4LyrS{4l>2ln_l#Qdo_F@^<@(Pi z_wwfdtqJ|c0ru&*@~eveg%t6`IsC!|{gM)wmzU10(+mIr18+%0K~z}7t=HLdt2ht_ z;Fi>qy4gYOi!pd3PUihzZ!Y39iRWa_7>d4eVVA%9yCp;ccGtST!LHuL2iP|r>%QK#tU3K)e-jMLrhiM_B$Ppl^5voxO((GV#jk45WLd@Yx<%=8teKFQ znR#yGgLGt=2E9<50f5$e-JK%Bhzt@jBO|lnPx}Bmntq^OXgMWA6h(FI6p|rkCT2AO z9RJh%pO%TKJ{M`=SW04MBt|#FpX!fiYD840*ALJ-3y7SOj7r6@4HSKz6H{?{1k#Yj z2gOSI8$l~dBBlzO>2Z7MW+9@_jXZXfzq;ixdDlZq93LBjlX zF6-tPvsal!z6O?kSz3EKg_4w#j_ADbN7Ft>>`~lEmv?0Yw>xxpRcdJA&VOlBS>j)pYUF z!E0b{6t;6UX8`_qjFt4Yh86X%qiE8)`IV`gO@fEE z+nTU9JbX{118yZRW4sL%;gUU%OAkSk1cPoif!DX+hu?S!)0&3AftQ~quOkm5y#>5} z{QUDc3?pm+FFx#5)>`}i0k9{yV>|$Oyf*Jw`^E$K8zCEN+SOWk^#A|>07*qoM6N<$ Ef-yTGCjbBd literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/bv.png b/apps/36-blocks/src/assets/images/flags/bv.png new file mode 100644 index 0000000000000000000000000000000000000000..56062603721dc1eb2bf18158359a539a2d203b82 GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfU!VDy@1{_`lq!a^uLR=XXqIdD=|NsC0jAycA zWNUr@nv&L~ms6^anTP!U_wQc!Y{8eut$>Q7JY5_^JdP&|v@mn3nzFI6sV{YM%xOpr zdAQc3OF-uT|NrZ^+z=5F z`Br&-7Lae`>EamTaXdLef^~6%NJE3+#0JMs4~IQY;!2Fo3KJ7rv{bBQR?4@!ET0!> ez~#os!N9;J<;z(oWa0|c&EV zIPkc;=7)^!tFG^|we`@_{q*(MK1TcN?B#!i>!GDVU@xsSF3l9y0RR9207*naR7l6o zmsxs*AP|IQtpKt`1a&64|1sw!k_*&>eSrU~rnh2|193Zwyfi4WWLKr{vM5Oc8smdA zaff~?(7AIRT}!o+fcC<^9l;(fg{Af;RNpGADB87RoDGhp(Aqt>T$Q7}VRvzi7CcR1 z!zqLY4Oler&VZv$3V>Auw8mbsH^2uP(3&lokY2PZOP}6Gi)+wkIUP3Uni5MP#>@DD zO@Z}>PWPzlX;})hQX@oBhI}fJo-(~C^tPclHhuKwa`^qC#Q*yGUN}+kw_sVoc>-v_ z`$*A%_ZejY=b`^$73H=fw3KhN!~#w`#{y2n`B>mI?JVH@R*>4}1EQ=(n#kA#H~;_u M07*qoM6N<$f(t9f7XSbN literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/bz.png b/apps/36-blocks/src/assets/images/flags/bz.png new file mode 100644 index 0000000000000000000000000000000000000000..6140a7c5defd2435cf0c437e890040b19ef73de5 GIT binary patch literal 1017 zcmV*n-`)EA`PmN{s1P~-|Np$#uadrcZK+N4^!1;`h<>wSvC*OM^y}{L z?su(M8X1@N_xG#MnW1=E-RjrV<;r8CKj-A(*xT6Q)y_gfs>sOYWMjG9-t4`gj>_P{ z!rQiAEFj0-ytve;K93P}biu#M$>P+d+Rlzmm>kc^s=ldYUS779mCvz;Z`i@Mqr}!b zg9U}8TF2AcQBkncxTss5G-#1B+p(afxqv04m#eJhfO4F_Y1$mNDHBECvMNoEnwn9?O`K%_avX6TH{eGRHU z_1u(jKc<1>TlUjpTrM}8XJ_N_lkE|TtD>E$xTXV9B7RaGOqKG|=B^N!#uOnvo9%S6-Gow~wchf(P9& zoP^2xX|on~4Cy+}_1SZ&pj_E6{a_SW|YP26&ql zT}k$O)!{`?;iZlcGhtf@{B9bA!IvaS_OEVkZmzC^q^a1*0 z=BqgsG21sh;IK$bivM*6YWbo8{E{Jqz=xSsEMhh)83uuu2SA6pOl2*1hwb*m(AD=I n)^ip4$Y03XpA{c(y~z0ka-(My)mk%|00000NkvXXu0mjfNjwu| literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ca.png b/apps/36-blocks/src/assets/images/flags/ca.png new file mode 100644 index 0000000000000000000000000000000000000000..27a9b2f7ca4172198ed73ddb0a0e7c507e357964 GIT binary patch literal 404 zcmV;F0c-w=P)X-ySqPERtEq80S!q+K~zY`<(A8G!ypVrFHiBZ0o(ciU+tpK(4=<80WH$0 zR>0Mq0cj)z92i|RT(v(5REimxGcQm9iWQiF%mvh%NCANQUJnD4@yP-}P9BNl$*u{G zC5E;MmIWA^5Lkdy6K=!68i;fg5>cqVKpzW{Mf{N!M-*X+O7tB-377@IOyYhnXa=wt zKz0Cc_ubrp@iCZh#?YKQn69MAa|iheK;>R}IQ9Mwr&lqYdY)WP@90WjrRe2YUUYBi zZT3jD+dwUc-(nc+HqWWq(=pJ#{G;TD`{7fn-6*ia2|w3uUAH=W;ZO#FdjIEQ-2Xt$ yG>U}4Jlm`*Gthfxpp?u&Yng#U{JRMk^nlE0RP|s34;I}ivR+F0N~UBjI{v$-vAGW0J_EiZK(kF-2lYO z0ClVY*3kf%xd30I0D-Xpw8Q|lb^z0#0Oq^^^v?jtjsS@<0E;sKet-ZJ0}*2Y00FN_ zL_t&-8STO8a?>yv1<j;HZao^uwo*av;{JNu~0>PP5{A*LQVjJ01gPG!S7M*r%JK-@C|0x zfp^7WY~ zhls0zWF@#NO3hgE-HZ=3PwL~B7m{tjRjf%ixXPN;f`x!A_@HUY`swMJECFu@0000yP)t-s0Du3l zy;|7IH1^OK2!i)}s*LZ`ANST6&JZCVisH`|A=*kF@wyq}a2@KK8q+HuOq#esmchow zMVhs5K;^}Z0003#Nkl4MHGT- zj6}ryjVlMeLcBb#nyEK*etFNA)=3b6qSZPJijkr%1VIf1Z6Ro}Cuj@75gkEW2>Q#W zU7H67MAf%z^I-3PA=|Zia1tOiYnLEQYfs0SYOSBwbG7bggnF&MJ}$TwtfOp;_ICFd z7KGdMI@6?`?zG!Y9Y;c&*6+F9o$=AAAR||1hu}SsM=q zzgtXKG*@cpgCV>eFy`iJ?MFOkz$#a>ljXrPbnD@79MH7+_s;B(v_tK;F9tNcx6)9* zK)-2O-doCeasXev-s1<@$8-k45Fr3;joZ4cLqAdkU+B`_qra`hc3DUK@AcuAn pVG5HyP#PT^p97Cv{urypo=O{bSF?!ySgPGM7H zSJPtG>i_@%oJmAMR9M69)XfURFbo4=uid7twGub)|FAnQJ&A##FswsP;v+veW-8lz z%4WaClR;-P*xca?nxcUdp6zyhxUpDO3iLDuc1vdrKj>jf5A;5FbwyseOXUV!Riws{kn0&G2+zC{9+0(@_#N&AHnZ3MBjyx_8Cvr3tL^;Ixv9MlX z&9=izHnpR71;P!<6xc1gYF`e2btFv zv%R&*ywE4lJFBpX?W_gU?Lv-ij|Fm$8Q$n&s|o58`}4|>vEPsxh`t-L0?~Fub|AXG xkzrjjqYB6wok|`ej*B>iTqkHWxd=XySKPe#UDtMFHK6wxJYD@<);T3K0RY8wb&dc4 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ch.png b/apps/36-blocks/src/assets/images/flags/ch.png new file mode 100644 index 0000000000000000000000000000000000000000..97f6cf22a650ca3680a96cb272342d689afd065b GIT binary patch literal 135 zcmeAS@N?(olHy`uVBq!ia0vp^0U*r83?x6-OW6S_o&cW^*Z&L*|AC;P;s1dHEB1Fu z0L9HbT^vI!PA4Zwuuf@Oxo~0P;-)RaDN(E};m*#79ZQ%)CK!rvTJ&%wi64WdP)Es zYnyU}tOX@(3Mp?7EppaOV#p9K|Ns9$SdZ%L^Pa25(?D2wiLV(qcz}?!MqQFBMuIR) zh41n9)!OELjj|&@edOism7>A%!^$~Qieh!5;H$YzW0vc;!S?w2;C6?&!PU&t;e(U5 z=fKLu%iV{TxURU*@yE{e)Y|jQ(ly%wNB{r=M@d9MR7l6=mfL!&Fc5`f4myw$LO2#S zr9i1|-~R#k2&f>@PqBAhS588HvzW;Qvi$-GV@{6RzzzkQ(}0LSw!7^sxmWn`0qJo& zPK>(32-!fz;WA3&Tk@ra3LB$0dL{hU}iH3t|E&8 zSlry5&spI3P2)QOZc8%LB~;qo*M{TF$M1K)Om#wNnAxO(Tr)*Mpc{$vmPj9krJZ4Gr+^Qkrq;{-64gF zvZ+TVIIV!L-64;_&GL)9W+6m;Wm587@0Vq?*V-(~rULlxYo!Nb^n=mIMcJ4VnM)wj zHfCPfA;9Z)_wtV(3)^!6-d+wP=fVygxp$21uo9PgzPJ%D9YFlY|ElJW_gNRG+0i<0Xev__m-jMjKw*} zS+0Q5c>nuT31bHup+3pul5VK%Gb(iD!#GuADz90_0;tuaMCPUPim_Ivls#_Q(bwlT z`HFYQI8j!nR)nwEAf`EPtiZC1*CZM90JmO`UN4V=Et9Db4 zv7}D{F$Ia~05Gi*pfgE7^t5C~bBAV<{Fa6m%IU8G8M*p#_}BCwf!i*Hb`nO>00000 LNkvXXu0mjfXcBe^ literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/cl.png b/apps/36-blocks/src/assets/images/flags/cl.png new file mode 100644 index 0000000000000000000000000000000000000000..63221a8f7c72d4b595509795bf98ddb8f00fdadc GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*mlx~1eh%1B9g8%>j-_n$MGr2dc z{6Ma5?A5#P=We)dleAsZZRL^kFTZ~O^X}u%{O*%8{BxsH-+@di@^o5d5~?9$h$HP9R)W%#)cJDv(Z_KBSrQ+ZJ*bKO|!l8TCSY3+WXmI_Z7#}JR>$q5c@jZGd75uBVW z40^O=LM_IBDPX^X@Tp)3UNa&)m#=;e&MA8OEMm1%##eYST(_^ am7!W~*`=a||8@i2z~JfX=d#Wzp$PyTbxx}Q literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/cn.png b/apps/36-blocks/src/assets/images/flags/cn.png new file mode 100644 index 0000000000000000000000000000000000000000..5524030febe24b9f8d040fee5f50bbdc4d753284 GIT binary patch literal 315 zcmV-B0mS}^P)jv z7$G~qRa_Ls7)9Zy9B`!=xABnRMH>$hUOJg8*%VhnFe-9WSZ2pbLaaeBM03KE#)ykT z7K|~&myQd|+2Cmr32?K(lcZGPDst~|B$?X+N1{E!nP8fxX_}_#tsb+W1H?mj82A7H N002ovPDHLkV1h9|gYy6Y literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/co.png b/apps/36-blocks/src/assets/images/flags/co.png new file mode 100644 index 0000000000000000000000000000000000000000..4e954f9f5f2e147c96e0eedb367e5a704fab5b2e GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*m6n}tEh%19Z`w0QP|7RKM>s*X9 z3U+O9R|QIGdb&70se$a%l=|Rd!coxZ|_m Uv0G-HBv2EBr>mdKI;Vst0LXeDrT_o{ literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/cr.png b/apps/36-blocks/src/assets/images/flags/cr.png new file mode 100644 index 0000000000000000000000000000000000000000..7565c71d06964a47e24d48e759172d1dd5c10528 GIT binary patch literal 398 zcmV;90df9`P)mI%`|0TW`Sux0r2qf_02GPvqn_@Wljdz@$J*oby0-Mhz?!$qmA%dM>D1lK zthI+dptiMpu&se?P>*OXozLhHfj%o~Q`NYG=kN3X`})}2*6ZNQhnr%XmP;v5SCO2H zt$i{pM37->LOy<6nxT3PazCJ?d$PfRRiSZvmdQ^`{!9P>0KZ8@K~zY`?bcTg!ypU> z;E*s%HV{b3-re`VUUP=js`9{pfKRq$8@vl}JO?`P0LXyjKnETH|C1=eIElbGpR+j2 zW5#_TFeGuF?IHKOs;Wu_1E$Mnt$o|aw!pN^QAz11TWMKykg*P0Wav6kgIbue@i^<1F{)=AZuLZ6 s3%Jz-KMudey(tbn1L*$P4m<()1)0QD`RS#3_5c6?07*qoM6N<$f^o{bbpQYW literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/cu.png b/apps/36-blocks/src/assets/images/flags/cu.png new file mode 100644 index 0000000000000000000000000000000000000000..2a2ab70d06d9ef261504cf095f6167b34d76ecfc GIT binary patch literal 387 zcmV-}0et?6P) zafq>$i;)0B?G+UW1U+zp09r!^BDjeHwEJWIQUst0F@3%aw9*nJ6al@wkEP6;#wcSc z)9&O<<5wtqcGEHM^V7I=byf4M)2}?c*w*))5)tKpMVSlKA|hf_TyDyM6EPy5)D!@- zau_E=lTB?b0Bxe4w3mdf!?L`#xfzJthP52%>+4SomV5%pM=FrdDEZKntq9vJk?kDW haFQ)C+qAQPD?aW2GzB*!{4xLl002ovPDHLkV1j9atNs80 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/cv.png b/apps/36-blocks/src/assets/images/flags/cv.png new file mode 100644 index 0000000000000000000000000000000000000000..38f9393bf6f8a4ee6f8e7f17f2aed64783091a4c GIT binary patch literal 334 zcmV-U0kQsxP)007EKL_t(Y$L*Hg4udcVMsZUq^xy6MpLG}R!U-luiOZIrOVXUQ zf$$Ze(P%XO5a*1Ah{ir5E2E!9%(K{^z8Vt(fCF#4!cvb4L)Pao@0`PN%`{GE7~9eKGMk|tKJddy=?>_GulP~ gk?~Ii(Lv*KUVRx3FUnFckpKVy07*qoM6N<$g6KAx#{d8T literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/cw.png b/apps/36-blocks/src/assets/images/flags/cw.png new file mode 100644 index 0000000000000000000000000000000000000000..2b15273783f5a93be12c5f1b2676ac5fd750096a GIT binary patch literal 239 zcmV;=A^UIHCLMK@Ak96*-&k#VSBKZr^+m89B=>t0DwtEK~zY` zV_+B}z=2qW5yUFYB~BS@sAcE@VidA0HZ~{Dm2AcZ#M$kAW~tl0a402je($qxIj0aO_Y(m#>Ndq#*Xm@;yj%ZOk6z1GH@gio5)=lM!}E- pN<;z%K_bDBP)M||N5LpS2LL|QDadvPB}M=M002ovPDHLkV1gCyT08&% literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/cx.png b/apps/36-blocks/src/assets/images/flags/cx.png new file mode 100644 index 0000000000000000000000000000000000000000..4cf2b541d252e23744de6f45318ea8cf59cd885d GIT binary patch literal 700 zcmV;t0z>_YP)!_L0OOR&=%&+7pKM?WV|8 zDOI{7d%z$^xFsY%evZQ)w8$GBHC}RrtgW}tnZzB<%NQ3lc8r_6bH5?rOJt0$9*H#L|uLc9|k0005!Nklefv0;eIfh2I5E zK?cYf0UVF?1#+JPjz*e@1`QmG%n{8V;5cM}C|DoxDWn-x;@OQ90Y)Pu)Qy4}B8GiH z>nWu418uYTacE$yo#UsnbY-=e8;A)F{7}_pPvNdh5?O|27$nfztLn-kv~;MNFce6ezX!C?A4}j;l^YQk4Lc5L3bano4oi<-7W7xar=PF+FByAL=U?g`}nognnX>zH#i8Mq3xKJ zo1#Grcpft1rf9VR>Be{E@m4A*+pVa4n>a-n-0{e(2OCx0Ta>|NeBOr3k*#&Td1PKc*VI%oyM zut?LPTOCG5FA`v8B*4r_fSHjkkEbIWxczQ3Im^bDkwm>CH$FY*t8v>MoM!H}E)0000t3_u3 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/cy.png b/apps/36-blocks/src/assets/images/flags/cy.png new file mode 100644 index 0000000000000000000000000000000000000000..81198b21d8cadf4a43f2e4177fe5ff40df4e5848 GIT binary patch literal 559 zcmV+~0?_@5P)wC{=6Z!<^VhP`)ycoavxJUr`|#rR_3+@CJ*~8!{QLR!-oWIgRidepTxma%4*Htzwdze%_HT`RdnqAm2SMLa{#&WLepyUqd~?LY)Uzqyh2vbFw!eILKKBDJ-u{3 zA%LLoEg1qhI_CP3=yGua0R$bo01!C>89J0BN>4{}#93+ASRhhCJJw=CEVIy8Ym0Z7 z*3n<*qU*X7-Zovxb?r!$BPBx%(mIb5-e>VGix9HRBwmnNDG`JZv&A7c&m3Wx-h74w znfIC@h}E?k^bNaidQkOj5k_v6uQKe&Dqn3k1k=7z^_AfZrfOArjc}}K6yLaJ_=IV` zan&>oQRGnRxh@sM2d2t;*3}>piw#_R&Q(?7p{^9?Uh~-^8k6!?4qWmpaOIK@!H-7J@JkMbR-3#)1|1zgB|{#E?w+Zvpo_x;I;B z#PJLUnW2*-2%UU_%$o)b;wC>JY;poYlQR%A`2(iOfCT}QOOWF&U_tL>2J}tlK-Xj* zbWE;*X|e}{9FGAD8YfGjX|f1fCM%$RvIeRr>!5N{05T6f7-W`D3PB!r!i3=EO420U zp(O%>onlV{s`l!ja<2+%_bQ-%uM8UYN}y@40NVCe!ER541kHPS(6N^VJ$o6@xAzY^ z_m-f0ZvmcKLV}3BISARCK+xV7MD4vn+};ZW?u{UHFNNJBdH|5NP_ZdT=^y|A002ov JPDHLkV1k%ymVf{N literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/de.png b/apps/36-blocks/src/assets/images/flags/de.png new file mode 100644 index 0000000000000000000000000000000000000000..a60a67d302568a059f7a0856a3d8ee582fdeae0b GIT binary patch literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfP#0(^VcZ;R~Db4_&5LY05mx1B`Ifi3O8ZtnR zw5N+>h{pNk1PRs<)`bxVRw(>zTD_qm&~XzhxYWM-}QXbisWHs?2eJyBPjUL(e=T? z?Ua`5ijArN+B5(F0YgbdK~z}7t<&39gD?<<;Y|^oP-s=K3ihnN|0{ZdEQJh&%*?*& zRlY_40N%?-(*ZbbjX@+Y#vqW?#vovpasZJ%ZEZoTl=#1WZ46qZoPhe2@TN=&W~!86 zr%1_zij4RydO6eW0+_x&Fcl7E~{%fp- zVCr1O-_EIw1e?zNjVXy_P0G=U&)eV~Gxj0#hv3EsnoIw9cm5?mZzwqLj-7Mv$a=3U zI1jw`Pssh-f=B?SF1>fmJ@4L#Bw*z(4ba}cCh?v(Bm>+2L$11Uyn;vwHj`ff$PYwf z(BJxatH79eYrv>@VK6dY2#k)m3}*517C}k81yB}m7L>-D0p;;{P!W#iAUAHkfCqW}N^07*qoM6N<$f?S~mDgXcg literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/dk.png b/apps/36-blocks/src/assets/images/flags/dk.png new file mode 100644 index 0000000000000000000000000000000000000000..1c8f97e5031c7a083ccbc839bd29cd025d0bbc9c GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfa!VDx&gnpI+QlbGqA+9F`^#1?<|MAG_)3TN? z=dJqx@87Q%uZo|#rvMdLdAc};cpOhoa9}#qpXCpLvvPp=5Z vW`#nBk`^r$D;f98k5?QDY+cO7sl~$3pJK7|d}{P9peYQVu6{1-oD!M?ici@2X;BN%Ly=Vu>OM58*oR<9{aBJd3fY-JyI*=qb+W`3B zjh4kTKyhg@0iGA4{S7tqrlL==ZW`M^R{ll+G$1{g)fpgQ0^q$jKO=YRq^_kO+22t9 z9KSz`wAp7ZND`Z)8j^E=Z07St(_{ip%XtuZS^|#SZF5amIAD1SR6@U=pc9MC%ayf> zM$)0nVfA}Ctj1kmRX*~9tw*|3_FG+5`r~c7MkjCr#{$0qRvTfXJ+=sO00000NkvXX Hu0mjfr?AoY literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/do.png b/apps/36-blocks/src/assets/images/flags/do.png new file mode 100644 index 0000000000000000000000000000000000000000..b9a743f5358f644eb3dda03cdacb0a1fbb13dd08 GIT binary patch literal 396 zcmV;70dxL|P)d1y;sVTHDd zzAqx2Ra9fCbC+_6jaFFKb$il2PkWW3k!N~PW{Oj1iduMJbpQYWx=BPqR9M69)3*}B zFbsfU*&%_rrT36t=p8*kk~vf&ibPYID+-v0hJR%A){G&6 zjMeRHZ=a<>dKD8kk8Ceg$#B4AWt-2nWbB4?!>$jOAXtLFJ966o_c>$(A4fi9pzV7F q_U-ik(_Q=K6G$L|1QJLf7Wf5#*J13`j8l;S0000=GXMYo(hxN3lA>ZgGp-&p@UFVoDM@xUGxpBa_}1L>zsVR| zGK?!T)EPVc>FnlrjP9he=!KWL)j^6nw!n6HRmI6 t>q+FThrgG@<-oBnhjh**U;^F}_ylA;LU#nO0l@$O002ovPDHLkV1nE8v#tOD literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ec.png b/apps/36-blocks/src/assets/images/flags/ec.png new file mode 100644 index 0000000000000000000000000000000000000000..c7e081a6b9f2b6dd335a141eca89c220e7c06d9d GIT binary patch literal 933 zcmV;W16urvP)Shn%Tn@ftFAKOrZMN1p`i^?HnXLL4)nk1;x7|99^U|YNGwy0BpNKWJ(%HE*V)s z5#PxbqjDhb#sX}GgHkyWE@X5Lah#i=h|3==dy$cnn1<`qD3N?Js+CGQpcF*MNjj;b3`lW%gIZ*`-p%0(PjqpW!_Tbz$|mL)~iyPtq~ zV?3N=8Az9rZILQ+fpl}KJ!P6fg3aV*jAnfR00Iq3L_t(o!|jq+liDy8MkO1|!G^^Y zH!#g~Fr5&V-h0{JdwS>pKgH}104B;)#^*_QM)%D9t^|OAfq}u_a1i&u55zZzzCRU5 zxH=Tb*zIFWzcnSsX7A= zFm-SvsHa3d_a(p4`!I#R4g?7BUHcKaDfs}ziwi&!-c)WJnNEiUkR8J$zzUu4f%8hF z61fP3!+|~%xf`DYUjip^q7|zAx|=??!{PRG|3@qmY9(;Ch@7RdZP9Zp3d;&hZzi^2 zN=~fLO_rF*Z|~#!@U70{G8Tg+66;mi5R!tc+3fUmcDP=9V-gCnSVEqM#FJN1-s!Ba z-A@GK`5i5$t!R)TqHdv(7ZgPhydDZM+V&1WZ-s(RBD%6&g|BQnZV!Q+)b@^@LXz^h zZTIE&_xpuSpYVXh6(TCvdnk{}vRr=Xe<|V$X(y0|(OW?t zjb!0AO5_3V4q1@497jC`RULTd=1qw?p$0(kI{R(na!n>#DyUa9p75ANCsWn6;ZmJK zz*_Ny)>_k)Hc9?uHX9m9rnFY8S@9;MX^WN4gJ5ImWNNh4vhzCF!$;>e>GQClHR(N! zyM)xMp-6ma5U_$)d(p_{_Pb~XZ~ifc&=4BJ|3ml(WJP`Tbo89N00000NkvXX Hu0mjf`DcI@8P)i@7nwK?BU9T&#O4vzGvyzqrsE{_GN+$00024 zNkl<0|QfwFRGp)h^bw9HjyL>L%d zJ}t9+D`6wqL+|a%ej7@R!sze$TZvV8l_-TV*K>~&qwr{KSH{&CVid+@v^^z4A=lAs z+1qks77$d(d3I)M*vvZ<2r6WY?8rIRF_o}Ft`#pjI{LZ@Tg@=@bzjH6nM5QC&a{lS pG%Pl|5D6HRhyhxg#d21(RhIGPD=m)002ovPDHLkV1m12c&7jW literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/eh.png b/apps/36-blocks/src/assets/images/flags/eh.png new file mode 100644 index 0000000000000000000000000000000000000000..46d51eb3e23db347e829f4e41d432faacc821772 GIT binary patch literal 396 zcmV;70dxL|P);Xg5g)3ZV`b-+hDETw~&hjq=FKuaA+hvZJ+wRww`f0PRUcK~zY`t<=kw zf-n$-;SM@&SCk~)0mt`$O&89H5f&V~Y7O5xKLljI;ZATpkwL63WDwZ1L1y+7Bxe7C zyzCdq${s;d_8Z8_u0Te14HB|HK!5fGg#P|`HU$y3GF{us!eM5+roN^bbZ~*lvGO#u z5?x@Oy~9?dySc#k>;^$Zv~z;U|4;3P92Efi1B*PczlV!nO;U=KzGk7uKT#f%C1b8C>0TY<%l3375r qkd*rZiy0H-^v&*Tq^g4 zD)Vb9>MSbwkt_VFEA)0M`Ijr`A1cr>H=+Ol0gg#TK~zY`ttOzFid1vWyF|lRE#tr0yuw|1tKT^A+BsPF;jF=Pv zh6!PMPIudtKVC$s_X0%Wif`u=-EB#u1Smj7ECPudV=6DNZ|}Qh6VAw~qEku=bQYTf zfBgCNdq0IDNvVk@XoPAKNpn~TA?&ui8^vf$8F|P?)UwZE2e7kq29PRT+Lk|-6W9S% z7U>Sa6Vc`_!a9c?Kopa19moXu=wf9OJA%<`Gl?KV6l>MvBz6RmL`1j{6&AVE<44#P z2qkCX?kw!2)7Ui#09&jcw?H z6&dG~2AeSwnLG{jwE_6M0hcNe?y~^CI~l8}spF{wt^*^SNd|guAGS>nn_LLRmkRH# z1k$G==bZ(!rFftq5UQb$L}YntZbyn#61rp}hc6PSf(5HuU(&BiloS`djHafEAk&@_ zpHnj9vLDV{3Oq1#t8fmiD;SY<39?;B(q*fJe^RfEc-(Uf%Z3lNt(dV2Afpr?L0Dsh zAP(7r2eO@~`M(Qqe{9Kr2CHsdwi_I>iv+GjOL-ejsxm;MfGMw+hjB*$dtLygJ4X;d zm8o`Kynd6texE1LA>{x70e(qDK~z}7?bgR`gFp}l;Kf_%7)&$8VB_8^?v7i^`@c{w zQBJunQk01QwwF&c(#&drP;fvAmS73~53o{jz+XS?C;&97q;YgOPmRwM` z(?DNb6)~7rNg-fQSvZ2zcN|48rfV53Aw`rrXwQ$Cx`=^n3*31A zKq1X~SIZ)^sKp1eD8jmutd*f8P23whMZ5!P+eBCH_hk5^7fA<~Grj$74Or zN2A{rb%memRuqTnUz73I3E%Li;QYT1+Dp00000NkvXX Hu0mjf(@G|g literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/et.png b/apps/36-blocks/src/assets/images/flags/et.png new file mode 100644 index 0000000000000000000000000000000000000000..5ec27ed2334c840baa2ed042ec6a0dca6cbf7816 GIT binary patch literal 571 zcmV-B0>u4^P)8UzQ_~wstrqRga?T*+7cT4-3f-0S|L@OrXD|KeRAW?8aiT-ZGvpp#Ui({ zIeLm?TyuDtpH0iYDyynN2Yg2yLZt?TISFcN?$i-TH-y3$E5WxhgeX`Ec2c)U?Fs+@ z0gy>VK~zY`?bXY2qc9MK;a}2Bj{>?NuD)P9dHyGheb!u7L-gtIJjD!#?m)o^KvS?g2jlRRj1IpjN=g zcJO}Q4$y7Tpu6=`^Q#aAfbrmm!9#Ozq$=&U3I4V(c}RaI40!BLtk}rtiE0!nW6@ zMvDQ4o_d%KegKSU>YXok&@nYliaO*Q-9|9w$(y|J;-Wd9Z)xer>mdKI;Vst03$;tga7~l literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/fj.png b/apps/36-blocks/src/assets/images/flags/fj.png new file mode 100644 index 0000000000000000000000000000000000000000..adeb4f1aedf0e87ad32db9f71a5e8943d2166850 GIT binary patch literal 903 zcmV;219<$2P)=JfdZ;dh96im>YI z?cl4q)=XmZ-r!uN(TQYt@$>YJXM28*v(<k zw8h4}4Jp=|1&gD(m(a23#sJhqTe%?~x>gXoJ0`4}*Bz z;vn=4X6{iE0k_#1zeYTRA^iIO)HX!LOAjR-&x9#qL2Iih0Lj&;Gt#KAt2sD0v^m%$+8n~a#G1I!x&X-H+j?BNMvQB(vxuLJRwp3?G9=+!g^SnqPvCelrYH z9Y)|7V^X5<{r9x(dkk5*GpCpb6Qn=%nIN-1K_bs_0yj5jc`+W(xIEz(yeVJ|Lz|$u z9EA zeEU^vn>X3r`1$+OJyzLQY~J7C_0rd@rl!%mjqtj|UUHwKc3S4Gx#s2N z%go7ghN>+^ecjvJEP3qPlqAEuk&cq|S_4$=w zNtAzYN_SRmd!e*x=LLxParRNN$zVgMEp= zX8?j*?uoj97=G-Aiqj+&5n>0GYFha^e z$QcNu4Su1_vMl6DESYxK*+Y~Tglw3L;g!=PIQ0GK7vys9%mZY{X-^n-~(FqTJf zEJLrj-^k(~28jtXc!PAQRH|rHHON~M4Kyi~RZBvxP(DS04w_C+D~u&%a)m-J#s2_R zF@~kL7~WZMI?rU_^AAPbveHsuX_{W3S-P+|3ifNW27uU{UTvTOo8$OPZOA3K%aD_2 zS(fH$+9?B{iai5B0CrnHC^mdD54-IcE4BzKT@24MJX5dpXXD_z0XK5>L=s+RIr#{7 zW6YK%7K>Rdx3X_2aW;6FOXI^qB;mLTjF9A#Se3;}w$W%T`c{%MPz}GG&Di7Q<4Y@% zy0~@}-1*(!-CbXAw|Cp?UHK^wbK?V6T%{h4>>)7fH-pPB7l{P#yzpKE&@>H$B{*N> z|NIM($RRKY8}K>9WwM|x1NqTAR$@pw*7THQn{iRw|CSDfXh+VXfj zEmMZO5-3D4eeL`HGrz|^2=#hCmE4SQhzpEtq=h4#a;vLuDi^VCZbT55=qrbdwTd@o zh4Fg5k+Ki5H@Ww%PeQTyv6!k^t;G-98#&}tfmqsQW60^A+DvH?sn{X`2YX^Z@>ON z|MYA3&37x$znp#i*+=sSbAW1UJY5_^EKVmUNX%*oZ18AZ!|0-wQmEh;yJ6BK%|btu zAhk;q{j^-FZt2Xl5WdMO!7bq??^*SBL-r literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/fo.png b/apps/36-blocks/src/assets/images/flags/fo.png new file mode 100644 index 0000000000000000000000000000000000000000..e0f45e816325ec23cf2cde54fd6862fe5c882938 GIT binary patch literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfU!VDy@1{_`lq*MZYLR{Y)J21rU`2YX^H0PZC z*WNa{man%?&;zf;&D7#z=e&E$D<*VQ_`SEOD5D}RYAzZ6^8;_7jwCb201D+w5Uv1 UE^%?@0cv6JboFyt=akR{03Ey_t^fc4 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ga.png b/apps/36-blocks/src/assets/images/flags/ga.png new file mode 100644 index 0000000000000000000000000000000000000000..3e2f30edfa05ef988ab0bad11e874aa5e308a9e2 GIT binary patch literal 106 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfS#0(^RJg>?FDb4_&5Lc_xBMkEr{#+DGT&|=E z6qNCFaSX9Ioy>8RNy3eled+@(orI8r0?xiBM}CIw|N0ulCr3X9s$=kU^>bP0l+XkK D0p}cF literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/gb.png b/apps/36-blocks/src/assets/images/flags/gb.png new file mode 100644 index 0000000000000000000000000000000000000000..d476f54d931a03506fdd4886a0933a373330c929 GIT binary patch literal 395 zcmV;60d)R}P)J!x%g7Ke0U>F?$l9v4&9=bQ^v=}m?)3H3+5GYI&eY;OIbGQR z009$8L_t(Y$L-g*7K1Ph1<(hJlrA;XB_j!aTL5}q&JiZFRV?+*7fqE%+r=K?UmoUj9o4F>aq8YYXD(s3H zz!@n#c1>YOLWeXt+C?F|87k70Ar)>|*E>#?0005INkl%q-nJ|GmRZK+1T>e{e))f4;qyHA%NDRKHk+b!&sMN% zfz~72ms~4V`(!JaYn}V#8Tk6^$Mt#xKJ_DhRAc{i3ySoI$GJl&LkDUc?BB zWa~${1<;>dXV;kvph&iI=T_P0yhTuC=SZ%0i8z6hxRAHpeNZH6p6_$dP4aEZeb7SA zIXfsxvQ5ogx}9?lpoqj*Ql0Ahq^?|S96SS!!{Q+YaIP3dtj++^!OR)J{h>FKBU+Me zOR~kd#2LWs>$d+|7m`$pBrhWFU;_YyVdPsrO%pIpQ~u@yZUF@tzT-RV6adni?>^uF z=s(z+Kz0gHntosdbRUPtuw=3WfR6N9aw zOM%L6)d9Pg-^DE e6z~IGQ%f8IkvAd^mEE9)RIHefg$8lA?Gyvn<{5;?NxS=8_uC^ z1zI2}z!_-2DZo6s%^v`Ys(Jvc9?j6uzf|{|GTPVY1H1qA!Y^lW3-k^CaDC()xOWad z6kA}6K2JI@Wgj;vwgmq!_to7WE`ZygCI|Z+e4Sxgb~|TH(SgO--Oeq=-c&g~nF8!t n;ZF{B*Eyy8BsJRC2LQhS%*9Y9n~1sk00000NkvXXu0mjf1vays literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/gf.png b/apps/36-blocks/src/assets/images/flags/gf.png new file mode 100644 index 0000000000000000000000000000000000000000..9c109485ba9a1dba869785bd49c0762a79bfa894 GIT binary patch literal 468 zcmV;_0W1EAP)v#~~E*7iG zQp(g#3yU%0J{9)63V=i+?12xp%u!@hCBvXa7Jw~#MnFOi7WB2~c_iEcGg7_5;Wg6j0000< KMNUMnLSTXhamT;_ literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/gg.png b/apps/36-blocks/src/assets/images/flags/gg.png new file mode 100644 index 0000000000000000000000000000000000000000..cff151e3297b780d74a4080dd3eb676032bf1221 GIT binary patch literal 236 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2)*RDe&2>kC2M|NsC0yesxTzUbHC zQ(sq0zp+#MSg!ciRsBPr(kmscPknN6PDQyu_066xjv*e$lLcIu5Ah@+|JB};s#Tz%u^#pmM3^6{IqP`hx=XwA)`njxgN@xNANeNfu literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/gh.png b/apps/36-blocks/src/assets/images/flags/gh.png new file mode 100644 index 0000000000000000000000000000000000000000..6cc9d8f43bd6e118ecec335255588f15258909b3 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*mlx~1ei0hw=V&??a7_#l{TTN~{ zC;^4*GPn*d5RevU$_V55a7@HRi{;i<;U8y3uiGmgnc{OCsA8t4i(`n#@niuNA%h+* znNW)vBD)fp_Nzy*NN!;G#>DoB;W>+vXpxD)$_*xSJX(X5J40?rIkqfH&CHy+aN*@k zmo{-|Jh>^w#deXML$Z>0k-_v0Pem0<-@5FW#GO(3g=vwEtdv*JcF7x#VZy?FL{-C$bNQ4`8655HWa060X$ovz%*8(0iJ^4%j!%8bg=d#Wzp$Pzwd0OBA literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/gi.png b/apps/36-blocks/src/assets/images/flags/gi.png new file mode 100644 index 0000000000000000000000000000000000000000..9a6d2b43c04fb57ece918329022528780a52edbf GIT binary patch literal 615 zcmV-t0+{`YP)X^=`k1CIZ#> zd6v{^`?)NiZCWQ;-uEG1UR8s+v^Tou)?Um|Re1-2h2LF7#dG$@g--^Vud~f7?V1efupQD0BT#&N{vzSZf z{0HW7!H<6oL>PaM3ZC&C8JvsQGsMw?m(Ku1{(AD92ivR!r-I=aixU{QSxp zHZYLHV*mgE^+`lQR9M69)?2cJAP_~-1M*1o6z4zK{Kk8gP6I!wat~nHNP)sH4iET% zi$SeyRC*O?9RUDv)Y#_1V(<~|lb{OtlZi9nj*D^|1$Dq>MvZ~m;HE^mUT+y#J(e)< R*L(l~002ovPDHLkV1oB&tz7^B literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/gm.png b/apps/36-blocks/src/assets/images/flags/gm.png new file mode 100644 index 0000000000000000000000000000000000000000..5522729872c3a7b1b185a1a09a1f45522e179bf0 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*mlxToYi0e5)HLG$B9+{s1|Npo4 z9?hN^cgrW{y5_@VpaOGG7sn8f6RArcz zj(r52i3LGs0a}X!f|CRlC{=lT1dbWANdN!?Xh}ptR9M5UmWguXHVi;XilneQC{g!) z+sWqtKd_)XowZ!bmD0eTj7Hu#o-NK*jd|YZCi;)`stZF@wRX7XXCz9|HXj z*a0xB-U#+ziUA;a103)^vnetFWjha1p?d>N@ZK6k4KN-7k1WiF#DuDKvnJU=gE7ER zLGt+U>~7Lz?!%>I$SgnwuwqDtknO$5j8`Tp-Ag>s9hQy2;uSS5KxPyb1T7eA_Fh5w zc<+HG;Hrbh#HqCa6KJ}2fPe*>?Gn>MHzrIaW4DiE2s&ULbh>MvTzX2%(79s*N#O27 zg|(Z->)5C`Q~L@CMmIo(#_a}smSZ;vPP-KW_o}M$-8M2vV*CV38Y+Oo)yO1`3#l4eF9r z=M&@zAye6lUUG+;7wSf9KEWS}bVQ1IIq$Mad+H&PQptrhnP9M&HHYQA%M$(Vr6)X( z3v`~VcAH;-3|3Os^*OIi)Fk&Fl6rUi+rqzPp5Q|D2*G9V_2@b8*N=}+1~%k{Je!IU zvhVv;da2DmBV}3Vr>l{QRPqNgmGsLFWb8s-Ot(-;1zn;~bzmXZ_Z3069qw^TZ_xp- z-J+9mD`SFVva3024|&_gnPXB-o%`4A2#D34UmuKO(TBjTz^Qgk zsvuwUhvyz>a`dr+=Do~ zIL;4hrU(xB3vs+DwDB2<{fI?aJXRzX=&pB(SKv%h^Y#ytwSY@+{j+s(2g$4DQz;+! z9JDjsG~m9kNZ~(iHAG&mMxW#nnIm6sCCf=&?DxDQztJ$a$~@HIyUvNfkpC?e<`iR@ om!w>N>^ZS|Jl6f_L+5Gv3;S7NElN6RjQ{`u07*qoM6N<$f}_mqtN;K2 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/gq.png b/apps/36-blocks/src/assets/images/flags/gq.png new file mode 100644 index 0000000000000000000000000000000000000000..ccb0022f173c9dcc5804bc7df19024b07ead91ce GIT binary patch literal 634 zcmV-=0)_pFP)RD25vq1m;{s42%;~^OT|Nrpv^aOIq_xbtM)YQkv$HLRX@9*#S_UHqd z1M2GPN?4M)FFDpFA_#b}AZD~jn%utI^0uOrXt!wb@#N>{pdg|k z?d{Y$mkc6^S`&Ycf4JsKV2q^PLydxo5q{$ z?6kRFYmdR{JD3O;fq}G^c@ciX6951Kgh@m}R9M5U)N4<|Fc^km+G*R3b|MD@FykJ?W&8nQ84n;T;{ilv`~^W7Yak|L9pv-Nv*#Fml=jJCfs_HW|1s-1G6Y?j=Sc)j| z!pXBoBfAC2hs*@MNf>If9muB!sK()ZJ_*MyK_g@7jmM)UY5SA)X*3&>#fT7!c|yr5 zaP$Q-325m175EWXpzj0zWh){YTrM?8A`5U1d$gwr-EK9gzXIMAXJJv-RZ4#>w>da9 zcglD{Y0p}E&u=k07*qoM6N<$f_V-vnE(I) literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/gr.png b/apps/36-blocks/src/assets/images/flags/gr.png new file mode 100644 index 0000000000000000000000000000000000000000..3fec1ae77376fff0e13a5ea19b7b5c4a6a598d46 GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*mlwyESi0l9V|9Ruqd$k`veEoIX z`s=6fzB4S_oj&XA(!&p@@48#MS6>MiVgdAdh@bH9<%pM|u30o8qLm@LtK^{EdFL>otqh*7elF{r G5}E+hM@#zv literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/gs.png b/apps/36-blocks/src/assets/images/flags/gs.png new file mode 100644 index 0000000000000000000000000000000000000000..805e76fc2c50be5b7f96397cd00dffaa875afac9 GIT binary patch literal 1269 zcmVEs zYnuQZV(;Q|mT5kgmlK=qQWN2*w4>j<*!vrE@ zqO8L%IZIfEZ9gL=Z88tfmH}RLq75ThTtX*NQeAC)pK)|`GCeqsn6X!4d2@-dAvR$l zSf1&#z0*KgW>zpVA~_fwPsNY{vAD}ZKRgW$5P68Da(jeLVVKfARpzX@VulTvo&aAL zC@g)|Yu7M_Px*%-9YnOaTbGVnrw`D=eRatogs0`jl`uMh#_N{7MJt6p=D5Q=T1GWzqQcY4gqr}4JphV30F68VLqo~WuazDi z02m~9863jeuaVW3WfC2#$-Ct*0009pNklwNz4zX)w}1T>uuyND*^l>Tn91yBf3wTJeOZh*(zJpku$SneDHwFmYXd=Q zc}i!*-WxonY9d=e$f+oumZskgl6N{vHS^BuL}OI!6-iV}>|xjRRfR4av!8(o+XLRc>;)3kSoT zH!C}Ke5l8SV~Xd`Xqwj7LH!x8f}Gwl@%%#TIAz}D#XC)rZi^b&7Omre>(l2i19&?~ zy)&9M_=^v~P}ZLjK?2OqVi@j<#bQdV5C%jJ5j-s=kJqud%QfJ_?WM(J03d=OP}*_e zWwXI-@Xj8mHURpj;Nf#i>TA*(wpb?$piA25X&PqE)l1qyrS}nky>&`VDJ=i(}Pv3AWX)i<~ zmbr75POa5~8LTKaq;9=Ib7l$ed%S{UjA~wIUxajA&O~;>j-uyi@)X=Ne*Ep4S zuv7UOd?xP(8^JUy0=vX=oZsvPsSwkfYue>LSiQ8}3oIm!JjFMHTfua0Q{27ZUA{kE zPqGZtSSGYOir4=86Hp~}jipPHf}-DFTj*02D%1$QxNRlAHq{orK zAu$+~3_(Mb+|3L|H$a%FEGSVxVZp{4e4NjwNI6St9C((N7=ZL2_G?7nyw5kk6^(j! z^p&-sG>$YwtUMOd7!32ikkh&SNb7(7{-)_g5rIbI)0oW$pJw}Z`(iOnrUHQi(wc!i zRvh(uy`X$^Q^xV!^)=dxp*X$b9u-$jazefw73BSs7$T@VS~*OZOmcCxD7#JW;`9nY z6ysdNE!XZ|KyWAa1ym2~H_5W8uJj+yn-T&tC?A}>fbOG%QREo{JU-q3atoVQB73!s f0S(uj|2+Nzy}W?XrbYT^00000NkvXXu0mjf(jh=l literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/gt.png b/apps/36-blocks/src/assets/images/flags/gt.png new file mode 100644 index 0000000000000000000000000000000000000000..c3289e91f9a77b471c77ecb96f923a7ca114ad4e GIT binary patch literal 540 zcmV+%0^|LOP)TCI$J4#-+>ZD8^+}h|g}L8`y5M=5V5GB=`}_Oz^zrZEmYS`GxW}rz&#}MD zv8le7c9T}5xsuo7&}xlQl&O5-=iZjJhT`AY^XHxa{{GC`#Qy#Av&5ipMk?g&;rZ~Y z+~d^C&C2ua&|PRSk&tZ1*1gu!%ch?^w5Df(Z&0hWb?DZK+0U%!(}DKy!p*+5c6?Mt zekl3#+WGX!e`QOPltQbYoy@X*)zp@>wWrj^jnuw$_3NoJg>qH^009(9L_t(Y$L-Ze zZpAPR1kh1UA{V)L`}f{|de8k&l@k~UAOqQmd%g_^L)`Sv9eU@se+w40pam^x!M}n8 z0KzE%$N@mFI6yhvujuY|jEwE}>q$LC+jxQE(~t*?Byoo6!+BPs?BtkB`vNRz eK?_>&|G-~L=UqgXK1Fo^00000002+P)t-s#vwTX zDSNyjJd)e|t}00{CTq4RL}0+FJtbzA$?2H7+n2)QjxAQ9o4T5`(~sKsO0PCo@km_iQb;GeiPTCnOBB}!1@ zV?C9a5|p?RLMfK0zy?>tAcUGiOa<0F#q=#<38h%209~yoEUVcJth(+|fTfBr{O0v# zAWT%wvx6>IQ5WJW2+ez}_I8MS{f|oLAy}Tb1r*&9tDP9U=+QV-9y6=8}zQvwP(l$KqcE9${ zaZS@Uj5UgjUFZ0-rs_k+B>vRt+|xBSV-k-ylskp7D(9qIkA5%bpQRl951x8{0V2sI UPmyqmod5s;07*qoM6N<$f_`f-&j0`b literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/gw.png b/apps/36-blocks/src/assets/images/flags/gw.png new file mode 100644 index 0000000000000000000000000000000000000000..64b831ddd433cafbbd852cdb3a3b0f7ea8f5ded5 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^0YI$5!VDy5`z06wDY*cj5Z7~pYJV<@G0gL1Vqoa9 zH@q95pwG-PgGYKVzfvBDuua31n?RN6o-U3d7N?UF9M~G0EEo^3I5ctDgt-x|xkt3- z+;LcP=n2y!ks=9ofyEOpOR!w(G}y?y;@l*S)#}pH&9X0-v<{9 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/gy.png b/apps/36-blocks/src/assets/images/flags/gy.png new file mode 100644 index 0000000000000000000000000000000000000000..4b56e5e25974d8503d9eb4d79d405cd80331c515 GIT binary patch literal 498 zcmV&`ivbcDQ?(%-ykv5G

2wtet8Q8FXJ^K`AH>0t4H}nA^vh?L7CA0003gNkldg2wnJkMt*89qKNNQJ;* zHs4=DDTCJyrx3`aXqUu+lv4s;6+*e+M7B-kcs$A|_fd%DXFMH=M;+z<61OBDqwx2_ z%3UPezI)@*NaZf#jYlirwOe@O+l5WHCm!82-9C8q({@+*)D^EO?77Py>WGInJ-0g^ zhG^VwcvGR??SO|ldUqK!9=4d=K~xwS?ZHQaqc8wP!LRs)gvh~t z|BDW`dk$b=(F<4U>+9<;8#mt;-KJ!q(``!SV0D++@HFZ!GZ-N0CedKl(LmHa7NB1n z&_$iz95fBk>rjf$3N`9w2M=Vcu5Z93r&Anxorl?~gA7xMJ-?FG2|v6!RWiGx$E4Qy z2FOvLbNsS1t(W?|ZH-UM4~G==v4z9j!Wi1NS4k~T+rZPP&$W=20XEs(YaGUIt-K`X zR();+QUes(*>*a_fx{G}pc8t)c&MEe<2p=xk((Zi&I%g`pAvqGPJNr{gRTfYFL_r; z3N>YN(Is}BhIx_n$VCG^w7RS;(LRh{)MHxMb&bnBWxCKn3sskNyi`x;pw~F4Gob%K&Vw!vi|@8|NsC0KtS*B_$(}+dV0h3yTVFJt&)<>*VpYeHKQUT zn)CDe`1t()aB!)q*todgp`q36$K=o%*cqM7C=K8X7ZCIty^x*Z z4BW?sp$qal0I$0^oZs&yUUT!5EHCHid;!n{uo|ASQjRa!mI^?vI08#gpe4(Y*8nxQ zfk#K#mTAzW$R`j#FOR?tc?bUaqZn$*TH9m*edkmIP!CU+4{b9yvC36rH8uk{be;To zHTHON+8?_T;JSr-8@)9oCbA{(A6FKjbE6?iGvVyzu!1bAs#rvr2=k=LOx$vPi3vHa zFOmb4iz3{R8S`YYxnM`+G#*mxHvLplGrIL(z>xSna8jn|i%Jr|JkA*ROH|5p%GfCn z&sm@*@Ca)uMsbWV4Sm%l&bnF1vl#mdF&x&PzxE<=&x?t#jQi2;#l(Kj*r6;*t%{yk zsCqAH%&FuqmFA!|xOAdo%xO$0NNFsaZO2`)V;9GwgVEZd+(}g>E-ByU+m2Gszq%R! auYLeY5g#`Vtk^~X0000gle93mt94kM}1|RJa01_ies?e z7mBh=sogq*kzfs0I+xQ@9A@BDTt7XY@O_2)VPyZ@++aJB|NZ^{U||37@c%zQ|3ESyVMCicqFd{OhZ+v|_oOT9e9 zW-4J`sg|e3My(!(Z?pH+t8%a8(>?ies^FXX^4as&jaBRE_RdN9hb}HD=dHlsZ2X|L zt~gCMZOf&K|9vq9zfz*Md`y8z5|L$5l0;dKXOWf%kU|!r9E3bVJcK!fvb6jj2#+Al zB%auuN!Gm=isLb{ZEiB*Y@3WmJkwH6S+~qY$PvQpIv1nsJR$O*E2ZBZ{uBs^JWzZ1-1B&hbm$2V10wxHNYM7>>Mgm}l(Caa@9XRms Z_ymozRTGKb>p}nk002ovPDHLkV1nNXIdT91 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ht.png b/apps/36-blocks/src/assets/images/flags/ht.png new file mode 100644 index 0000000000000000000000000000000000000000..561b1c5f38a5a6571b78c0afc174a55e584d3068 GIT binary patch literal 871 zcmV-t1DO1YP)a z6qdG~im{SqmT(?%FHDM7GJQc-kX(hShSkcp*n%^$iz%O-u~U8!yP9-gY_N@u6JuqO zU6N?W*~bapE?ZZ~l(b3qwbk4IrfJ=e4gK(36SZPUvwOA?3uVITrf2}wr z!;ukEPhwY36>3bCmPB%yc^=RWFaTT)y|2!jevY1nY+W&coP%vwGK9Q^4{t7fZhBvf zYaWCsY;%?|NB{r<;Ymb6R7l6|&c~A4P!NUT>$aJ`S2+Me5+E`RIp;Vz=bW75`#*q} z_GVZ}RJqEff7grt>JZ}R=l7rYc1do$0Q?nxm;mCRJKzmO3eaWx>P3^U;fAJnClfH@F3Ys4GDO#sMw2T>@ZnA^0JEC3b-uOMzA zoL51V@_9*w>N(&RdRr)bsovBjdzR17W@7!O`bqG#5OMb`-XasbadOhIC!`fW+eP#M z3dMMbq)B($xV~=0yChAL@uILCeDhjs008!7l8{dKF%g?jAG>Knl9x6Bz}l;C%R$`x z+Da0Ve(L{R^q5)2k0x@ylZU=t6G^5ex%OKEh z-zU%mxFe3|u{&8#T@?m{!qqofzKhMr;*MKz``}o@iuh2tZEb2O%v%$jz4tJTbs#x#c$j&d$RJY|$=`=(Q& zlu}A7C1am4%1+T87%W$KRaf<_r5KT6gbxLEmE-hLq*B)1fCZXSxiF2%ZL%QucIl46!(!ERv$YXJFW)C8Nm|Ii(}?N1cg`yYNvB3Dy<{2HiZy2KlUA R^MT44JYD@<);T3K0RWZPBPsv@ literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/id.png b/apps/36-blocks/src/assets/images/flags/id.png new file mode 100644 index 0000000000000000000000000000000000000000..4d59754ab5edb84722f80f65c735248403403654 GIT binary patch literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ#0(@?yR}>gQk(%kA+G-!82$r6ef=ArP0m0; zX-^l&5R22v2@zopr0F8AY A8UO$Q literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ie.png b/apps/36-blocks/src/assets/images/flags/ie.png new file mode 100644 index 0000000000000000000000000000000000000000..4fe751fe49759374e26bc5c722c6dea94d265d05 GIT binary patch literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^0YI$5!VDy5`z06wDgFST5LdC;N&h?S{{R1Lo7}wCpfUVd3iXv3P>9CXvu_HtSSh3xZ+S?>k@4i27?XxJDDDD ReF{|0;OXk;vd$@?2>_RVB{Tp4 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/il.png b/apps/36-blocks/src/assets/images/flags/il.png new file mode 100644 index 0000000000000000000000000000000000000000..a760e5fcddc08c12d0fb48328a66c74c270278a8 GIT binary patch literal 301 zcmV+|0n+}7P)`fKWWJqNxp53*U{VaB~`-s`TnlJ>Fe+M2R*u%uH)UbPL==w0KQ2?K~zY` zV^AUzFboBSfziRH&9jq{0GrA{9EY5T{U!HDD1@3a9d3h$N^` z-PqVTA=s1+NEP8#sECLOA-oDT8$x_ITwEHCxN=Ow@5Tku2B(#j_AqbdBH$Snwg#Y` ziW~_}1Qe<>fb7%^;3*;$JPBYs7qBT&OQAXgD{)p6?U@CU;NW2=6g)%+IMGo^bfO?S znL!fnfko8K3dCnFqO&W}1;A*nFmh^z!KM%Z5US@MjCv8$00000NkvXXu0mjfX9;+C literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/im.png b/apps/36-blocks/src/assets/images/flags/im.png new file mode 100644 index 0000000000000000000000000000000000000000..b3074aef31b09112eb13a722e72c967db2271565 GIT binary patch literal 667 zcmV;M0%ZM(P){B=f@E!y%8t>|Np*ldhF}#;NalG5hvc=-OS0!+R@GX`}@6w zi^>!#z9>4z9Wl2VEWJ)#z!fUvU zz&1y_K~SYqRkvDY!nC%uUlX!JPPJrhxs7Y0Q#`+}M6#-<&Zw)yjFY{+y|Y$f*22Zn zuCl#*gRyE?!nI(;#KfkAI@#CG#-XOLmPOIUbiBE#$GB0)yL-A!8oYc(xud1AEFH9i zb+(pi&aw%T&p25 zzo?J)XE?I}00B!$L_t&-8STMUa>Fnb1<-3-(v!>%bKF3aGDAu!GxPpeQn%9;*qTm1 zatKMs z-ps}|U0ULqmeb&2%6<%TIG zao8e?%1D$0Um`s|b7|t+gD})H0kk4Qi407W7!tLq*m(OO$R)AiAp?dV#rd86{if*l zOCz_zkr{QB(R_`B>wX>v17v3_6_0n6isJC-(Pqf1;HcPHU)XpOhU0Eq$f~lZ9I;$r zo-FnIRvB6GPIY{=M$m?By&r6MD$u9cnsQdVdFVsEcI4Uwje6_GXqIjXy0GGk2x`~I z(8%&f=V#E!8=e+8G%^>bq1EhC1zHU(=tY?LGhdi_9li!MqV@m)002ovPDHLkV1mYW BQD*=E literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/in.png b/apps/36-blocks/src/assets/images/flags/in.png new file mode 100644 index 0000000000000000000000000000000000000000..39711f0edad5748d842d7502330d082e1643650e GIT binary patch literal 354 zcmV-o0iFJdP)LBAVZI8|BhJb==BZ?klNbrw6ooahRI)Cw$RV&#KYunY`vzX*Z24QJ2|F*eZ(Xo zno>`&m6OkbSGCXp007=eL_t(o!|l|`Z3Hn4MA5d##hu#okJX1xU;yc;AHV~lh0pKd zo(o>^f)~8t3;rGM`6iS;XD@gT6@!{tqY-C3rOrSFchVDHX;Kl40Hl?D52VaRBtjfY z`{&pvSc+z@5{}uo!4?&oQ+1}I#@zKPG0Vy%%3Q)s`%eZgODB=(636iE37utSj*+>9 zo$Bt0Ln?Hds+pq7*uE5Na4Bl0C7hdWgHD~jgh+^^lOOmg!z+S00H<=|?-_Ll0PbXG zwgb0!+cZA4zaCy@>r3u)xaa3^7rfvFFL=SXf0kezA-3s2$p8QV07*qoM6N<$g85aY A?*IS* literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/io.png b/apps/36-blocks/src/assets/images/flags/io.png new file mode 100644 index 0000000000000000000000000000000000000000..75520a336acd238b945a3a46cc046832f3b544ba GIT binary patch literal 1631 zcmV-l2B7(gP)Gs z|NqDkEmfcchu8!+DFZf|0cyI(eY1 z$4q0E6*G1B`1!!c+2iK#y294+!^+#=>hAFMlAyn{ywXKolE=*3YksKd>+*}4x~Q|u z=fBD;MuIafPwq3ULZO zj6X_}OID0)U7ua%@8aQkidTMtfmKCGcXQsBG^nST!`jC4_U_bpAL7VjqHTo*TgZlu~50VxXnl% zS50IkN^#J(nR%p%?a$c787OgpV8bjp<-5i&8CA$4C+CJ$OaK4`@kvBMR7l5_R%e@{ zJQNLsD_sy6WG$$;BZ|H2Iy!Zym))t`-}3)|#G3#KVVr%QdGkdtCpnPZbMFaw_nu)2 zd5Lh!)gUC;iXx zw1At}BN*%eHXMfj^W(dZpBQF4Bpim3pc~NyrlhcJ%Z+pGp7dv4Z#13k2XP0&Y|CZ< zvoQj~KMz6IYKsH-=X`vzy_odxi`tNu&DI+Srt{#j&HNMiS^ModmxI24V(pJ77yXIIt(Gi2;t&?Wn+Yj>u-x5j+#jsklYxJ>8jJ_aE|uW_ zOK6}%v(>Xnd*J*2%)3E!HO8qyw+I`Hr4^kP1pP6yMeKlU%q16YqVUWsKR zFw7^Ym0?J@9Y#N6*)TcVt-(pm!Kv>L2IFyiGN0d%wuz2xmoEwo7IuMQ-a{pSh=q-x zM8YQBK)qWoGv|xZygePX=cAGXfKsAlgZ2^AB}y+rnF;3?;r}jbLX+{lJ)ic+vrCkC zF49dwMsz|<_o6w_lxAA%6vb#qD}Ow5C;cBQzwgiPq@Y)5rJ4ul5jyp?_N8J>n*4 z_{y9IwPqS&*&ZyInj`IA4St{qC3;vvQk2v@%AU~ZB_vnqRTFWekqC*WeEvQ{s(Ill zOci}hwn7%!V$ekiyC)$y|B9zvAHC)&GC929MFKvJY*7f-n;7nGc*?^O)5&5_X%J6| zhs3h9Nq{;lnp9}guy}R3cXYIOc_qd@gN-U$f$y%h;&ob{8LDx$8?X#?3U>2M-s7%r zZ*SMvxBq}W8#Y0M_MB#P)Rl-{h?+t8HCZbRhe}lZ5&Zqvzgz3|)~~-tp~uL?Q>f&2 z)RtmVHv(5N+yV)!HPxt)gdQ9oKCjo$hc^oh>#7lXN~7Yi8A>R&!YY&!s;=W?3e?pB z!cFGj`sQZ6zInbLX^x{)FerFY79-s>!c)#--DqK1$&qfF^(e`Q508(J4-bdYLFI|3 z#2)Pw%hfy|pT1hk3mq{|PNpn0Vp;6{`0h_=mIv4;6+jmS8OFH zA)~PADS?bC-PG=GH;v)QQ^Xo=QU%LObcv=_t|pp-mFN=9<1a5@v>Xy@;B@Zm}58y8LhzJ7%smxQ6G2yqQpM3dvmO`xh7T*@d@H7rUyTAWk_x0)pG dC}IkE%75vLkqLdK|BnCw002ovPDHLkV1h{3A`<`r literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/iq.png b/apps/36-blocks/src/assets/images/flags/iq.png new file mode 100644 index 0000000000000000000000000000000000000000..b7b722731555f5440331ab270aea0076a2b500fd GIT binary patch literal 319 zcmV-F0l@x=P);M1&!AV3xR9M69)WH&iAPhxONGh}mNzniQ*rGU&Ta{ItyTD;{=CLun2NxW4 z&_M?s?BHu~ArJ01Kt7IE<fUn>s%N zP3HBT%dxP)1CXtIC8e^13V0K=CShsR8lr9>lfd1D+!P_)69vJX=OiMODv@4)GNyA1 zDRBe0DkZ$WP&Af!WELZ5>la>PybLO2tAG1*xCVX(7p5?@$w3DlbkM;LegW#8RlgBE R<0=3E002ovPDHLkV1mqRiJbrd literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ir.png b/apps/36-blocks/src/assets/images/flags/ir.png new file mode 100644 index 0000000000000000000000000000000000000000..e189229cf58b99f3a4584811b306e58de68b93f9 GIT binary patch literal 451 zcmV;!0X+VRP)_~`y8bF`?BtSoq zwwZ4UxdeWnpUpg>tdwkn??{rJ5+=NfTyhP500k&5yon*nYQN8)%=L1)w0q$CJAQ6_ z_03tiUKG}xtD?}>)$v-bmN3VBE~P_7xP;72$k|jCArP-kXqiAoSTfy(l#7ax81C;7 zm{f$!vNIytDYJ@jg*9fP9A%*O9okq*T&>z84uEKY1g-&|Py|3AaL{LMX>q&YKrlff;MhF?1I{sbxbHC%yw3+?LWm*8 t_>Axcvmx|{y>TBtW6PVPjymdp)F)T}C;mpR*)#wE002ovPDHLkV1f>2)(HRr literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/is.png b/apps/36-blocks/src/assets/images/flags/is.png new file mode 100644 index 0000000000000000000000000000000000000000..b223debc0e8f99529b5b18055ae00e45bf08b644 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfU!VDy@1{_`lq!a^uLR^`G=KTNv|BjsLw_|4- zSDyX2blt37H%v;_|NHm&2~<^8bu46SN(gzl z;!t4gm5>)r48jMwj>c?YVslhs2@J05pbiF4S3j3^P6^7Gk8SpWb3&>1h(FGKm@#hmXB{}i9 zw$?#X{q^?lsIlBvX8+d&{{8*<+ur7hlls~+_u1X)i4g6X3j6Kv`tZB?;9}iZ8RT{w z*hn4VVHf=O;QjRV_{RX%VJgx*CEs;#`|POlzsBpLmnxgs7ytkQD@jB_R7l6I*NJk1 zFcbyQr=mfM5Yb{3!;Wj)|Np#3tCG-clx7$QG2Y>@#}UBNUyygfCo$C zCRbYGnpRbFC0Z>XsB@E9g-;ltXcZH!Rt!|T$%>}snbzzig+OQ4(RKrozmU4g{4yyo zX<9F5M5((7U+&fI+Tms-Py;dG5acAy1Z5n!Ue+H0ul~xrfxc4{nxWViamJ5Sc9oThy zw7E1;u@jtzt#*y<0}(vV&=<(!a5Q&6K~~_xWP~s$8_Jw z>aO&PWpf{rP70jMdN;$fz}p6*N28Z%jZB;NpbbZ#5FHA1%+SF_R{>ovbY0N^ r$Y7*oFr+dXdvK7#(fm)?L*K_2AkdWYz(8AW00000NkvXXu0mjf0CIDt literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/jo.png b/apps/36-blocks/src/assets/images/flags/jo.png new file mode 100644 index 0000000000000000000000000000000000000000..432e4f1190ade80db242a12037f81bb909e82561 GIT binary patch literal 287 zcmeAS@N?(olHy`uVBq!ia0vp^0YI$5!3-qh_VpSADYF2d5Z7~pYPY)b93*{`-Ia*Cd{+*IZ_ttBv23_^@L43PwFnBW&AqvFifK9HdLrhC@R6-v52u{% R>;$@(!PC{xWt~$(69Dc>a~uEw literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/jp.png b/apps/36-blocks/src/assets/images/flags/jp.png new file mode 100644 index 0000000000000000000000000000000000000000..ef075bcd5b05bc75fcfa2f12a3603c9c7b19fb9a GIT binary patch literal 353 zcmV-n0iOPeP)=W=IZv^;J*tt{`~y$%hbv?S?#;W&q-TY?W&i*H<4Ht8R9M69*2@lrAPfc2^0d4}=l?%;Hg1g4v4vz7a@XX9KqwcM!GQ@* z@U>vvy>ot#W5D1P98oTGgHgjNI`)AcF2Nqq!A+bT)NmUk1wAx^GO$21MFM8q25lCA z9*B4WxKiNC2P2RPY|zmlvcZi8H5*)M@WTcz4O%Xk;Yaencep4TRHJWsV}phU9UCk( z82N8miH?u}QS|btc}Q$=&7z5&T3#xH{}eC%^~~U3uW>Qh(;VvM98>MF?p=U{`PgC6|sg#OP@B_JWKloUk!c%=S*MER25n#00000NkvXXu0mjf9x9(m literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ke.png b/apps/36-blocks/src/assets/images/flags/ke.png new file mode 100644 index 0000000000000000000000000000000000000000..74126a3aaf9c9c97f3c6d070c788c4242cacf152 GIT binary patch literal 655 zcmV;A0&x9_P)O)LveRkcpX_nb>S> zIZXwywy0jNntK~z}7?Uh%Pf*1CD~Ts{ zCWpL+>o%(7@>#8TWr-99U5A#GE$CywDq_}o6<&k^FiesmfF;6k#qFHswQB6>-{_|J%@RfgP^P`XMNaAl4ePLm`#c= zrC-vdm`=&F{PeadeIII9aJYVMW9$DZ$6pVR1^y{^<$p?_lI zm8X^cfeXC(G|x8nH$BEo;HXCDf;RSoZnY5)SQ}H)>~ubv%y0H-6!Uun|Gs&> pC^@i@S#e;cbYNlm06)N2fIphqWlm6rYY6}V002ovPDHLkV1kYkAu9j? literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/kg.png b/apps/36-blocks/src/assets/images/flags/kg.png new file mode 100644 index 0000000000000000000000000000000000000000..77b79c14adc95ef10eefa53224616d81c7b25dea GIT binary patch literal 615 zcmV-t0+{`YP))>Hz<<0RKn;|B?Xz;{bfs;5PsO0mw;2K~zY`?UqTB z+%OCT32@)UeUsGx|E3RPJLXLF931X?Kt>QKR)LU@KKgHU5a-D8CYU2Y7}c6G0>r%m z$O+SyUF@=&5&jqlR0}sjaxV3BLQ{A)J4zzym?77iA>&CRp^s)M4lDWTrIFIed2(qF z@c`GTQ!vDud8PEq_Ywn?qiuh|_oY)!YK<6U9I2<8^mT8q8j#2#vYC!2V^TPL%3?@@ z+l%3zg^~oEp3BIi&~cT({H}KpD5|17_d^D2c^#ggqbQ_+dqgdj9}D&c~Qb@>|aJBq;+@{+cn3>ptnrm)?rW=vDi zZSYwj0_@vnrXz%tEn{BS5FFFow#{#2_h=zEV~lAT?ET2tUtjMf^wo_qre8XiCtvSR zIIQVJSE`F+y!x|n_#0o6S$oaY*R%Ng7O=&bteyw#w+g7jNZ+4Uzz>uZ0gA#+kbz6^ zuHwTQ{ehw?R~#i(qH;t?pT+ITR6VFQj|^kV6w!)NjI)Qa z^r6zYo`*yrX(d9qsX4DLM&VT?Lu4o?;0*wklA=0EYUCZ@hT~H#kjaF}jM7XKgb4Re zvP7~-U@@pnWhOT!r&K9gdS_fo4N*VKp~sSm5(kw4AC3wpaUZj9?w~;e(?Kje!MUQw z*X5_ h+jVXOZovNn_zpE{T32^1W={YB002ovPDHLkV1hT5JR<-A literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ki.png b/apps/36-blocks/src/assets/images/flags/ki.png new file mode 100644 index 0000000000000000000000000000000000000000..49ca4c9a0330ac6cca8380c7deab9aa2883b557c GIT binary patch literal 907 zcmV;619bd}P)|M<`VBs+M=&E3Qf4r_a)m7u=(_x6pMxV*#Gdx@<;REfno3Fo;0zYq*eUy2$5I91;ps(Ljf0S~S7?{wr2y~70JOZ(Gf08v=)(Dd>1 zU~rxD%K)XX$HOQK*o*?va0JR|1k>2$z8(smsKeNq0mB&$&|e15C@9gl!usi=>ZPOD zRaL{koT{_S;CFZMy}kO{Gvtel&eY-AWAp0(00NImL_t(Y$E}nJbD}U9hJ#|jf&>#b z38!)iSg+Q0d;b65wNa33-OkRy>xe$z#MgXB0>J<4Xb5G{1S9E$vCkOW8gPIKGOQC zg9H8G&NNTLE=~QyI6@PS(%&QH283W#ndXRQ8HA!6;v*Zy4rY{R>~u1=oPyzbi%Dh~ z+U9xgQy?(=*Wf#~J6TJZG#VNc=~ ze?>8v2t~hyp68RB`W#2Ug~Y$zG=ILVi0(0%j4Yt+n?L@3P&{|l?CepnzPFpz_FnfC z^|9I6%Jr0ohU2{gBuPr%WlI1v7 zC$L^Fv z56x(J{IRhTt!{ZW&@Eoe3uRMpE!-pvdF`q7Bvk|5aAJXL?hit4eS-QdIqo&!G-vV} hP~)DMF0Q)?=wLE(Ev)ca^v*rddQdd`}keFfdF%3m({MQ+`B-r zYRu}_&Okrh$OiyPmH>%IAc#41W<01+Jw|vt09S;wzYu(~9ZRPuss`ZR0004ONkl3V`N6ola+3zG_AvzuM${oiGOkRU1g)P!>`;MLDT#m~!==mD6eLDb*EARyR{ zaI-Wh){X1QbYpw7G$_%HKXw1Ar#U;8du#!{>Jc zz(~?ZN2d>E_TB)LCpku89i^}vz=)l{(N1WD+I&G*d?Rn*KR>{&GHuzM=7aIK&ZAM{n)AU+7w*=MklSxYjg1P|Aypg?T`_QptpGPNrxRU5(HNSbwAnZU8qd08~T(L_|c+&dz|c9MHoG zqN1X;8 zLWM^xf(j4fK&;r?$1=|%XyS=kO1#G4^lBvWSRf23O+S+;kD?_NywT-3u?Y^ICEnk# z4@cR(#-NV(JGuA>ClaqV$ay0jkAFDqCmx^3yqaJg4~GFKLxpD!*7Af=$1??+cwpig zg6=$RunSKY?8H-p9eGNyD^Cgv-u#|_WqfE$UNty)!H4gVmu2`jOk$bm*YnE3e;(dv zUO*w*2O8c*9j_ED@o=elAbZtYsNh`_ViBzH_(iGQLRP%rV3mi$gdg!?Tb>9iJXjVd zd=R(f@gV1|6rPv}|1n$G@-TRXtDSF4yA|i`wqTb=mZn*j13cVf?~>RJAn%|#Ks`^a zw-t{EtGvH;7q<}S+3j8t)bVikM+Y7Tw}w+7r4Bp{nufaY>Vi(ZnxNplw&a z|Nrmw&HsP@@i8>|b3y5QXRmL)6aQSk`g8lPe@~x%ickHqXzACQhL=o*+(7LoJzX3_ zBqZM+v@CKq{Qx0T@?m8&{) zTRBX%LQ34bEKoR=9xY{wrriMwM-P->|>$J*eW8|Y&cpfR=0EIrlp>* zYGRjPxp~Qi_xamvS8h%=4Hdgyv@t!S=$_By&Ce&L9Ju^oV#$WnOWMt*XzQh>hoAnW zo^54d`{woI3&$&^1@C+*6l;pP`)SAO&+qfadcqBY5O9OMR}4>x-S-DlKunwpwILPC*| zk-WUTPQSmuy|2X~U#xL&pOZCL`Q_(AK7S`p zn6`0=)uXY@%*+HCzw7`20;x$vK~z}7?U!kDqCgOafgWxRLOmasY7}YJ-PRUJ_D0Xd}Edn^yt|e1M9kl(Lg-MXLb#SagZSt14jX7Pz_$=h<23 zSj7-5qj`PF0+Q4gc-1B-)%<0v04<$aX&XRuh+u{o@?fy&SBFvQst0o-7(ea-b@{40 zUM|PonXy+o!39eZ-f_r7xv}7)P6*24EqgXg?`5g9Thd+SL`jVr3sh~s7U-6ZQ*I`B5BwCkVL7Nbr>%D=@^ z<7);_8W#lqJOq8~^oAnu3B02rn5?x@LEV)a8E&tsMHEYHWh z=cIYzj*UOfypD}$3Lc;)HAJJMdwh&2OJIVm&vV=ZnPOOQ7*JDh(x-9#6*cw35a)$? zQ!k#&c;&tEZLGG){z#|iGPVTe{JBgf*}ST>)qSI8bXKFqVsY2mH+_QIR#b*_Ae9SI zAlm_lx3R4dIZPKz1arDCkH>wH)Fz)lBvy&T9}+QdhA!X1hQ!Q;91iwGk3HZy1rSs0 uG95;I3Q%}X0q=fJ5d`y{Pf{Q8uj4ONy)ix7Gdt literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/kw.png b/apps/36-blocks/src/assets/images/flags/kw.png new file mode 100644 index 0000000000000000000000000000000000000000..62c6e4143f8d258921d66b2bbce0531a587fad5e GIT binary patch literal 233 zcmeAS@N?(olHy`uVBq!ia0vp^0YI$5!VDy5`z06wDU|@95LY10P-S~gQ0@Q!|En+W zf4_bkgR-DC3l~GK*-k#iMlNv%AJvOdJePsW8a!PbLo80eJ!i<9DW97XKDYf# zYkUVp&zSd~<;uUpvUnp00i_>zopr01ls2*Z=?k literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ky.png b/apps/36-blocks/src/assets/images/flags/ky.png new file mode 100644 index 0000000000000000000000000000000000000000..99c4e14238467d1f75cf678a03f3c05766ff51e3 GIT binary patch literal 977 zcmV;?11|iDP)E~ zgsToLaY|s3L0OLpC~on?%g7Ke|NsBiOk(cv^?r}D(Lq;MYnxSTo4gM!`1SXCim>3T zxd2Wm!^3gBxth1F)K6f@wh4j!mDlHb#hsA4duGAeU+lF5)bwP|gwj5O0pVCUn(P=2#zfMQyCI~{jIca2(#nNC-8 zjQ#iIN|0!0dp57Hm#ANM+0T!yKPlX{MP`nU%Cv32q*~u`gTa$(Rf4uGUy{c$N7`R= zRC;_lZm9}RoKSnBWsI<&ubbcAz6(&G0*o-Zy~EJMlhm+9^WWqbIA6t2GV#I5=8~PY zTUzIppun(7KL7v%OG!jQR7l6|)pv8EKpX~O5LXxV4!lrAz=pj>V=vLf-cl~TUa#N( z100@Z1j~4V|8nmDGt2DnVVPYP1UErwu^W(i-axY)_;zu_VD;i=+=T3!N#|u!1sd$$ zX^)*jYeq>bz}e^^^rJh2a#7}RiChAgIDq_17NlP$7vPII73rRW?iX{$X)xC0!+jwL z$tn1C+On|Nti!t6wU2@;`3tT@UFQm-iO-)<;|gltG3vT9olKr2#er@hE2h7kq?5Eu zC$Mu$_xt_xGuogJ7;HB8CSf{2r%4I+_M8)tiEdmrB!nR!{ysDXXD#ohWdnL2os;yy zhJ|f`(1e?9@6h?ew)^LI)|LP+`YjcRo;Ho!Ik5EUZ6N~=IaT?n4jqobHcqiQfQ=+Z z6p3Q3RFcB+EP<)EFH%{g*uDU|AXVU4s@1|$r5KK@LG>6^8!SL)<5z*%ajhc7rAp-@jNliEf>@Q%yad2>$%%~Znf)NUb}Zdlpj1FJgt^|c_Rb7`qS(5O$r;E`$Z)f)a=OTEMI*P(p%jBvPqF zgG~rLC1$mN?r>V5s8Q6~xW8{$qa!{hq{D7aQ&NcJViX^tS(YC0JWodo8mGnOLdrRc zmr?o5btY}?G33!fB$A`^21K`jKmZ{B^D6TP*qK-^J}gvW00000NkvXXu0mjfMrGgI literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/kz.png b/apps/36-blocks/src/assets/images/flags/kz.png new file mode 100644 index 0000000000000000000000000000000000000000..f38537b7816e4514edffbd5c4f72f713698e6e98 GIT binary patch literal 552 zcmV+@0@wYCP)CI;;Cb+A}W3)QZd7hxO%D+KcMDXuoR~a6H7_F zR_r(p=D>=0)@c1yvw|&2X_ShE)_TzK;Sv$A*l4}vRPju$>vjCmOd2-2bIE}PYw7rO zD^+Y%&*E6E5uTy_^Lb;oZ8}edUIoNXZRbv!v7|uouOX<3%%5VZ3NE5#dG3 qi3l$eW@5ZZi+RS2bmlJjfBXW>S`kMk_Qe1I0000

HqG%C;1UxE zh~Nm;@N-zG?6Z)guJlh+!3W0mPG&8KSoUyL3UKiYJkNAI$a}?bVutxWXN?+%xdkeA zX%>lG>H*qc4_ta2q!e6XZCI)1dcpcVlWmduMb)Djoz|-aWEmK^rfs*Ga%S--pz|0! MUHx3vIVCg!04@1lE&u=k literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/lb.png b/apps/36-blocks/src/assets/images/flags/lb.png new file mode 100644 index 0000000000000000000000000000000000000000..3c9a624c768d73fc0e1da8abe9c24d19efaf9c10 GIT binary patch literal 432 zcmV;h0Z;ykP)-NI;LtOn^(Eu%2cs@;PL41`0{7Fj0%uNqSd&M%&HZYO~vKYe#M=2!It{{ z`@FcQ;=sOW+)D8P00AsXL_t(o!|m3~PQ)+_h2ikmcJ7y!dH-i+F*6KENK_;%)U&QW z#fh8Py)BNrzze*<{{e32@_zEW&7F&3Ze=RuzR>FefUa6)96U0Xc%ki}O_f~Y0`G_w z^`=^oHWrA7lI&h_4Ho7%P(UH62Yg(>N!<&yCM9OtZ1Y45$)xehIA#~=UziyCNONLH zKu#hLS7oks5={i4)w?Jn6Gca#(;ka{*}`Nq6^9z!H?7c+sgk<~R6qcRmmo-(y0!o< zqIPecEW0Z{OmuaL3JUpIb}kb~lDg|2)hFdMKnfFwqG)l)qhp*qx|wvCoSA{{C>!|NPMw00030|NnAc3CZpM>%tWI&K1(||E=WzeA4**+DJb% z1?=qXQ&UsBySvTJ&8Ff13=9n6;o%7g0H%o!EG#TyVq(jv5qx}nv*!OqL`1Evt^fV; z`SR6h%>T#Minr(e_vC__j#!V6kB5hc<{AAxT6*R7l6|(MNW| zKoCVyq;{)bD*+-2iJYVNzdR3&6NZVphWrJ*bE-@7CKX8y7=MD>d$Q!VG^uy+#k1;_$ zB8+z**|#!;aU(uSM<+mHQBW{PM=m5UH2@SqWKy@&hozOe zf#R>qR~GyoS+ZdmC<9=FFSsI<30H)&;(-8jtL6H0V|de4*KJ$k7S|eI5j+))a?E?@ zoRPI#getYx>f`WHN-f`~UU0sBgPI+O(G4`+vw<2+Vr=oO9m%L`Z-<53gWG6q_KqvX zRd49lPQD~HH{TI08>uubO3e|F3fNW^p+E=LN(!#E!dnRha)excOsKV zB&cK}!h|A+FDZ{YDf+4&omC{xks{DZ3=IGP0uD(;K~zY`<(A8G-9QLL8;Btx59Xbj z|Nqe}B;8zB%CV&K&b^*FY5@ZPpHlSl(C>#BfPA?o-hnS)ANv07&<_AVO}m{`N@~B} z1@^`HBu}WG09HVByD{{?zzLAP4;&S=f$Bd_RrTo`72HlZG)--onRU$VqI>EonQ94< zRsEpnqIL#ods-TXjb!G*4Z*WyP=soBo(P`0f3N9@~)8^IFcPUF902I zZ2%}or2r}FEKLNzGNe*z<9YZ3*avi40!TZ`Cf9KWIOG`gW@b7{ z8GWykR7NSIl+wpO=<~Hz7IJUvmqo=^_@by-3n;}Gdev-4XLS)~B zm%n$Bq0)7J0001$Nkl8^d8Ieu6=1m?NwnJYE{FdeX4~e0WL?M`=1K|WlVm21bF0sQAjKmJ% cw=A#26FaFvPS8^DQvd(}07*qoM6N<$g1{+vS^xk5 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ls.png b/apps/36-blocks/src/assets/images/flags/ls.png new file mode 100644 index 0000000000000000000000000000000000000000..c277d325d7f55228be1952874c5ea33261256e73 GIT binary patch literal 319 zcmV-F0l@x=P)U1qH8tPg-(zEAa&mI>^Yi-p z`X6SzH~;_u!AV3xR9M69(#r}1F$h4>CK?+x@BjbU&J1noav*LBUP4ykK+wm-^E}VH z%J-V{=EHm75=2>sV1#%aJFxT|V~)iP3?ZwYw;2e+EQTOSPALzv0@ti3Sf|~TH82Om zDQDm#ume{;!Me=A&R5+EBz{LG;A-gua@14 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/lu.png b/apps/36-blocks/src/assets/images/flags/lu.png new file mode 100644 index 0000000000000000000000000000000000000000..3fa288d1e62e9417e65b1ab8a4c10c93f3474455 GIT binary patch literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfP#0(^VcZ;R~Db4_&5LbqU_ugt+{{R2~>$^p_ zfP&JVE{-7@=aV^(GD*0xo)n8|W$odbq;J8sf{Q`#q1}bqd8JQ)${0Ld{an^LB{Ts5 DqM;uY literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/lv.png b/apps/36-blocks/src/assets/images/flags/lv.png new file mode 100644 index 0000000000000000000000000000000000000000..ce27b5e30b5a0c196c5bcd50252a64312cb37e52 GIT binary patch literal 94 zcmeAS@N?(olHy`uVBq!ia0vp^0YI$5$P6Td*S&WFQfvV}A+B?kO#lD?Uvc%_cA$u` qr;B5V#O34!iKGYiG6B;qk1#MaeDUA-iOUrv&EV)Yr5mapx6%bOO+ySeDA5!(V@87_kZss~T3*;o@|Hs`tx=R}FQ z3+m224&1VtA>ePW+PPT_4+7cCS5{B6Z>p;2dU5(0r?tqBTVJx~Y@KTHA#-!Ha6*H3 a6F;Ax!I@_@iQ9p;GI+ZBxvX0Ao{ literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ma.png b/apps/36-blocks/src/assets/images/flags/ma.png new file mode 100644 index 0000000000000000000000000000000000000000..863a5057df9804ea7cbbe204a33cc5553a493546 GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*mlwyESi0eUhUDgC6!yvaR35`BM zURmdKI;Vst05igN A)&Kwi literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/mc.png b/apps/36-blocks/src/assets/images/flags/mc.png new file mode 100644 index 0000000000000000000000000000000000000000..d0063b68f5eddba97d9174d72cd77399f634db98 GIT binary patch literal 95 zcmeAS@N?(olHy`uVBq!ia0vp^0YL1)$P6U6b0(DnDYgKg5Z7~pYXATL4|}xkBv3@e s)5S4F<9u?01gi<_|Az@vJek!PjHlXNh%6Ns1Ijaay85}Sb4q9e03*B^L;wH) literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/md.png b/apps/36-blocks/src/assets/images/flags/md.png new file mode 100644 index 0000000000000000000000000000000000000000..0cb330a34494f04b4d901c631b5bb03c94dc8de3 GIT binary patch literal 610 zcmV-o0-gPdP)Gf(5yGAWDL^s$&H$^80AoobOg|P}K`)zcP=t6D ziC-&zT0o5v9G`IoeMJ){K1?k)8nAv_LQENQS`3kBN&q{QEG`qifd^hpG+bdgepnks zRY-U+4YmgGVvW<52{E5d-q63HGoB}#Cu4ka#-Eibw9vLE$si7r0PCd^#Qp1M0t?a{0Xo}-= z%z@`rZG^mXQhH$|YvUNle2r;FNM!}AxwsPIzVG|Ke-J4bSvt!EAl>6*-}n7V?gFxu zGHeAva%%j1vLzPS=40h@0AYZv=wXN*^-)e*T4eyv8Ka7}rnN9-I!|8$BS-+M5vl{g z#$MJ+fJXr+8mgi7mLgR*fQp2K*lz*fDiiT{D)YAsed)Qvo#5|t?jM8y`7huL>NgNb TZ&hS%00000NkvXXu0mjfqzUBj literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/mf.png b/apps/36-blocks/src/assets/images/flags/mf.png new file mode 100644 index 0000000000000000000000000000000000000000..b60655982f170cb956948cca32ca9bd31c6adcff GIT binary patch literal 123 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*m6n}tEi0l9V{~6Rm&IzjBOUMh$ z@10<_#|tQ>?&;zf;&D7#z=e&E$D<*VQ_`SEOD5D}RYAzZ6^8;_7jwCb201D+w5Uv1 UE^%?@0cv6JboFyt=akR{03Ey_t^fc4 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/mg.png b/apps/36-blocks/src/assets/images/flags/mg.png new file mode 100644 index 0000000000000000000000000000000000000000..470be988e8f9a7d722486ae25019fdea78750ef6 GIT binary patch literal 132 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*mlu&?Ah$};#)gN1<|NsBj#hR_X zvhUyi-H&`3b^&E|JzX3_JdP&^II%T0Suh@6aVW5LF_*ijQ^RIMzlK#88X3(cLM>Jm fggiVE%E1tPbIzo;hui)EH8Oa*`njxgN@xNA)|xC_ literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/mh.png b/apps/36-blocks/src/assets/images/flags/mh.png new file mode 100644 index 0000000000000000000000000000000000000000..f179353966ff590afcedeb9ef3102ff6f3b2d769 GIT binary patch literal 641 zcmV-{0)G98P)jP$El5AVM zjd8a_*rMxj`+eA~*5P6xT8jH=a4`@p#O=EZS1?x z89DMQ=LB-ybV#asH5b>&xj>pLnZdTll?3?=TqoxlQjA#FON)H;M-CRq2}Th`x~O5A){0@A(=lB6jO2J0Wx|S@^HMX!s2sJ6{i9U^Dv3D~ zpo-@92N%itLBnYc5@w!o+WZ}cD_^P0`4$58B>~job!7Tii=-i=c0uk=rKd8+Scz6!cvewo%Y% bylhneXj3ZDd-%y>00000NkvXXu0mjfv5nS*+b#0MEbN&o_0=rxqAKEB zDDbx{=!PlpuqyGrE0Elu5&!@Jmq|oHR7l6Ym)W+1APhyBWl$>){r^wB6-2CtMQgJz zkA!UTa14>SXR{A)2sm^MYdC6rCOqA1V$8_Ffhms|eSkqXWZbyTjr~5?QXoghm;^$! z-BbJVFrSgVy=I9R64!|BL0s5H3Mp0)5s;9ngoAc3H|?8AfFfQb6w{WVC45{oA-fS0 z@tiew2}en3P`)7_<|?89&7yf37m?8g+MPvwm(ay04;9=IIn#F$j}p@PV_aCyhO>d> zn}pFU1N#gY1Y)b;iXTPH67tn79W&&cVdfRN>=f^J_HqLkkqR(SFiSUoj|+QQk-@IgyuQGOPC7qh+a~?4xcz(V9aeGxd%jg<-(y*(WMogp!Gwk+Ge6M zEtYhu+oo=8@tv{%@6!v#VL&Sm=km2IKb0@!0*ibFAYW3**C_HukKKwOH%qyl;~4E6 ja>I$-5+gV5*uNEjxrix(EWrf500000NkvXXu0mjf@H+N0 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ml.png b/apps/36-blocks/src/assets/images/flags/ml.png new file mode 100644 index 0000000000000000000000000000000000000000..427d9d3b291a9c441d29961535bdc88ac91e0622 GIT binary patch literal 123 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*m6n}tEh^xp}t8;>Ce=dsM4OB?l zuN!kUgApjD?&;zf;&D7V!GX=s%flg3K+>Q`OD5D}RYAzZ6^8;_7jwCb201D+L?4~5 UY*ZiC2h_sg>FVdQ&MBb@0PoHrAOHXW literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/mm.png b/apps/36-blocks/src/assets/images/flags/mm.png new file mode 100644 index 0000000000000000000000000000000000000000..473e622a7a8dbd4b77ef557c9fc206f1219dc124 GIT binary patch literal 463 zcmV;=0WkiFP)K&&>L@uhvNNCCpZxjZ;q>6f>c;=+k3Y6P{?|J2WpVLy ze(%V|@A>b2&V21iSNz%BZOCo-wY&JSx4Xj-tyMSmoTT)Vn==kqJ^%m#ElET{R9M69 z(%Eu@AQXV%10*(O5to?6Z14Y=F=9HFDjb%Z&Umhr(NBK`zA_JN;0FF9u&OeHWtkZi zA}?40R9V3ipv(#i0Fe_Mim}arEygy(ZRekxc!OexxfH$;Ltz|>xfTU-1M+O3G@#4{ zPQ|$9Wss_3Hu3|?`KqEJZ%BWTwUIO|S#!6?b?`U59M`$yCFZBlV$CaPLN=JDHR zDcg~Y*oRu#p3;dMn+N2g!0tELC4*M8N(Ht34Rs>e*`Ti(?t9nVTN`Zm?i=9X95ONI z)9GxE7;)d>0UM)S2ZdbCagzl0<4a9O!`^3o3P{+P`#Bx6Jt*0f0+OP002ovPDHLk FV1jUp;+Fsb literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/mn.png b/apps/36-blocks/src/assets/images/flags/mn.png new file mode 100644 index 0000000000000000000000000000000000000000..608ac2ccc51c93e7e87184e0c44010b948f78a5a GIT binary patch literal 304 zcmV-00nh%4P)K6mk|R=@O@Kmy%8bQEpt8p7Vexg-J@f8;DZKU0y(p83~2X8!*E6?tAUgjf9C zA%eH9-tFq3wK+wVg=VLlj=r^ztv)=DfbsYCzuMO5)FxJ*kxP(IL5os-w5oQZMasu6 zTbE0(%qGhK00Fc~L_t(o!|j&Kc7q@gKoJxLL=r{uZA|k2-`D}Q?P=46m_--fMPN{G zW*m-+(8YhWM56`!#u9qwPvRj_tzQRMo;Q>BY-tUbKAHzZ6rOby3 zF?4|`4AYR8mt#f-iLq~g&>Ymc+)##4QMke8$^3QGIw?>a1TC7^aPq%@jcWl>M8>fs zin=y6-uDr%bmOQ@3>eiedpvKvs)n9k?`}404nD=Z(S`TxgqW9bLkMXzl+wI7xTnEe zKhscIq3V-ghj!+dnUTOyMS&Ft+6H7a*&_8Rm>IC zo%!q=hUlDZ!dL;HK{8XXosAM*^HmcVvnHr`trOp;4Ha6{1s9lCGO9R+KG(2Bng8RE zR%xA9B<;eYn~4kjb+iZ_Sa&__yteN&URDa~X-pRAp9^~-$xDd;JEaX@&>ne9(duV< z6-9@jX&-%~PY?R6at!fe!{K;bw~_(pH|@#EKjs5P_!=#a3}WB_00007)x*Aq`2RNk5&)aB)#7Jto;p6Sp*x~{- zp3BV3rKF;~zr-L)slvp@#LeT*)Zz8@@C7oK=jY}JIGGMTrRAW;FjQ zyW65_Jjv4O#I?KI;OgbN(7VRsD@lv$?A(u&mPt!euCA^NJ(Uznj2&@H7EXS#w!)pB zrY2Iaw!Fqphv@7=;hbrnZ$mV(7ZJ+56*{B?JDNM^5adXI8sT9J#h7(m-i4Uh&b>RAKKk^?&1YqLfQ^luyB|D%FiCue zc)4thn2VCdEpaSjoL-rK~d#jM)4 zk-OBn=d_sFhJe>38_eUo;fQ$Bd4jpnv?0&VcmMzcJ4r-AR2UiU!Buk`R{#dkPn5eW zUNJK>%d*VOw#>}T4l`rJoKjL|rr%e&)5lI{c9qARgLnSdIlNuADO65}GP++O6euwD z9V&OWUn*Y`#=wf<_a=ZEb# zAA_Uzj>n^qs(CMsX~SS>BWhxXcZZ%;^Gp5UhAzfNM?x=Z-Gg$e|z`f|@Dq`?*~-{!{$+yU6Q{rhW{$UvCxm}QhHC)y+ z$`Wb|WvTn{NExuKtd3l1J`J`cpIlYSX`rT6BobLDin54AqShLq-59sOZf>@MrO<<| zxj6v<^9M(%f1R-cIA_T7dz&RzutRTrI&`hCPY%GGa8rle2{X!8I||oJ=Uc$mjk}*+ zo6$#Ul+~pviaL4%hiG0aV^DUEgRM)Qd09{|^8=s>MWrcf(hNXqWEN+mS?}2~u+-F& z*XCx$dA|*27iDP>Q6e+&jXl;7AgZ4Enl~Ov*$ENlr`?q59_Xg;d< zB?Vn7#>`p{T(7h*vfjtq7>0fhdEP)2?l%8bCOFcao5V`G?er(soi7-qNCVwlY~SQYY`K|Q^_ zdIN-&d;zP%qs9SXx{QG#9n4^b3Sb2I=B22C9A%9oW`d1TqJ+cP6o*1yV@rfx46Kul zFW^wfGuhY{u9Ee#vE>0=iK5Eb*b?FohO)`V#>;W09(G{t8Lw?i4a>L%WLOp8PG+Z# zk-#22>5-=yq0Rzt!e!kIQ)eB3KZV0oS_e1~$O=3WI~QBcZapwu3IOa1i7p>U>zP5S Z5C8=JexANWj@tkL002ovPDHLkV1l0$mc#%6 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ms.png b/apps/36-blocks/src/assets/images/flags/ms.png new file mode 100644 index 0000000000000000000000000000000000000000..da5f849c888fbc6d38a2b1d57e0f14ab875ae35e GIT binary patch literal 772 zcmV+f1N;1mP)Ge z!^;4D9z9iwr9BANOkzP8#S(>_+;af9F1 z$SGQHIz2=)RYpZAqh&9dDj*_wihz53{|{q2sDy^QV(L5oZ|F#Vm*?^{03m>J zR1v`{aU3MUC(Z*=Nee+C0KCQ+Ovr@D2E|0$8sQmK&S{bY?bVUDvS*M?qR2IHjg!DG zp-2b(Gq*v8Ein9N?$Aml7sv|P48|!7%vg8P%PV_;XArw$g06T5gC6sr;P7B01y1nz zh|cqX7mS6>RKKj>NSJd|OmO-Aq%B)d7cS6gn-n&B;~<| zj$#}Tf@i1ls<9K!6IWx~CFiOS^V<*$T;rs*Pj4$}gL5t4?J+=#qYejY3u%M*TE2JZ z29*>&i8{U{*&$iGobPs7yG$m`e%G*Zz^=#{15`im#%^%4B-dYnT{xrUw=uj9v3Gg5 zSm5Nnnujpr8yIUpln6NT3mmmCCdD2!YmUS@K{=UBmdl#fxq+}juGK3}aG)cEN+rGX z3Sp64sv;*iREdI`C1ZsKI0d}9)J?GoNy!K$E8JkAZ-A%_VY`9qHNc;PzPZMt{(@9R z@&N>eT&r%7^+5&rlz6VDwra8n{EIa7Q`=`BKl203aXdi$G$mvJ0000KZ6LR|m<|Nr{+>+j#cKY9H4 z^?_rTFJ63j@7{S4?RW3qeK>RB{=8*hZ{2&ob3YKAI(6#Fn$7Fhtz(+jrw-IU$%8i~ixzr7_DtpK-V#N My85}Sb4q9e0Nq-9vj6}9 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/mu.png b/apps/36-blocks/src/assets/images/flags/mu.png new file mode 100644 index 0000000000000000000000000000000000000000..8a5645fd461b5153d387aefef513536110ac92c5 GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*mlxToYh^v%B?kf#ThNXf3uQKdE zA>yx;&{Jh5w!CpaP=SG`i(`n#@niuNA%h+*8A~qbP8OcU2~QeKlo*>0CnkhEyb%7v gNhKjbNeC>>Xj=SUP|id+45*jE)78&qol`;+0QFoXt^fc4 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/mv.png b/apps/36-blocks/src/assets/images/flags/mv.png new file mode 100644 index 0000000000000000000000000000000000000000..727768ac509c4d0e4111a27476e56b7a7f40f72c GIT binary patch literal 243 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*mlzMHCih=jF>Z65w#}Q&c|_w$R&RvEl+NNq!W~7*;h8Lj^B!{OD)=e-zhHSJ zvaC%_V0l57#ze+@Qs*2}g*(fXwKwilvyzeQ=#?ySf8=SqbfSw|%(+XOSY4KV*uu&@ pZD)b@l(0jbW_@By7IPIcFvvPJJUAB{djses22WQ%mvv4FO#skVRqFr% literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/mw.png b/apps/36-blocks/src/assets/images/flags/mw.png new file mode 100644 index 0000000000000000000000000000000000000000..6a52c2e809f1dd4a9998e91cd730a5f826a5204c GIT binary patch literal 349 zcmV-j0iyniP)$t47Fl{QlnN4M0002=NklZWx@wnj{ykx4)$b4FBa=CZ7*5lfpB@G1;zU6~e^UY43R zDer_nAjVq~UR4WTtTe+YCX$&IESjX;Tew z+uSb4F+-vt7>F?#x6Z<8^QyLRRzWBTD9u=f%WmcsVFrmX zg<{O9UAPo-b%rrC!W2p{q|U(QNXxKbxXnPjO;ac1P*`4Gz-$Z$2JGc1vc^OL20t9nf7)RL!_jCxr< z+PrDHs(Z|!VIO~j#JRNf=E%R7ZMla~U7MZH$-~gGS&6o^vd_zOt*zkE$Iq^+c+BH` zYhkX(yh6RyJ9m8dwW0KxjNFf&o3OR&kB@ARe;8r0TmS$8FiAu~R7l6|)kSv2AQT2* zDmWw|?k>+=>ib_-SMVk!gAVu?@SStv3V42)SMV?|PY(kOXg~uR@b4gU>pF@~Gl4Ee zc^nI$`)VGLS$R}PN^l6eZO9HfAYTh2R7W6;H9?FJW<%c;M37+Hs%`<07HG5OJCnQJ$}c#KaeJlG(*rI1d9#CN ztq6xjkhZw0w7{hWHq+rd!+6_WNfAiEGA$6Pmn#ot;eJ0& zWm#^fFXY*pZG##IgqKU6mp|cg5156t8{6~J@IH=eyobO}QvFGxwzUl7AQ%qPs;oI? z88I($ZfBV!G@EC^x|p)_f=X(RlmQKB!2bjO0)4kA+swV|{r~^~07*qoM6N<$f<@I2 Ag#Z8m literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/my.png b/apps/36-blocks/src/assets/images/flags/my.png new file mode 100644 index 0000000000000000000000000000000000000000..30275a73be2978fb4732940b9cd9e0f5c1b5d6f3 GIT binary patch literal 398 zcmV;90df9`P)gMJ zh&uJ^6n)%q;bX%`r}kC43jAtEp5L9?*$I4NBAR3vfw-Lmg+QS-e0Hi(@v$L}h4F>Ct6ys?e z^0o=+pACU7KigR@k%0inx?ShgI?uEW*vLYUkB?VP0LGmKU^fVN9+I5^00F>BL_t(o z!>!fXdV?Sk22hH&b`%gXZn1TV+1I}R)78W_YRpYw=E883^YJ?alJzHU5%Tqo3=--i zgM`G`AZF|iM2t=TE5-(~V)r1id}I(O_6Wp?Jq8hCKY)bB$e?lTDQFn`31}932+i)R z=uNwZ;G*B-ynNTJA;`oZXSI*Dtyle~h=6X3Rzj~o($T7a&T{1fSgTRldF|5G2XFrk z0EFebMZf7n8%!N1Nw)w$t}BOcRceBXIlpE_$12LK`IWpU)!guvQ^kT zoa{tv4rAM|@+?!8AJTDKQk^bSS?9S@rBdqT3)3#&#@a7^RaRkJc}z{`kh)H~+3)wq z-HtKF3u$~(64&AY?bWbpXC|P9`B|nU0Jdot^Cdt;wd3|(j_$*^0NyRk?nBP+eGuOD zX?kPNAHFQ&L%W`R^$3TyJDT-`n|WYRQ%?kd3UUBU&@Ap0G>kg|8vsnuJnk5b0zd^D y08DVU0#pzw?j39xV1jsYI}kDM4cstP4}Jl?v3j1A8Z}A)0000c<7Io3j5hr4@dK7c%jwuESC+4yCtqz) z9HCfXy^6NQ+wb!CV1cmr)7kX)`t-xh^~=+ul`iOqnb|Z`$kXHsJA3Y=vH05Hzs%pz z+UPu3VFfvZfSSM!g? zSK}ZUfZ=2yAuQusmr8L-+%;-l>a^3U|NmDBwM!Pj1oBOBtx&LK#=X6qB zuio_)#?N8URdDN4@-~B@tDuhO5!CbQ!Qs%0R}QLHmMuQqc;z4gNy1o?0MdZB7Y4ru zCor8rI7#8enHTnp!I)10rC`QmSKiFi=HeBGw;R5`-9LbI0orDn1XRV7a!e9-hqvW)uE{^cpmoAY*iI66E*wIIzw#>Rp%F=iPM zw8FbF@$QPel2F|g2(k>o@=Z~^=%E>}68zv`$oUY!4_96#NaTIX6#yfb3BoCoBLB+e)yI_?X^Tk=OKGOQtVN_i0m*mOn2;ki>aTC0>^ zAvnaq*mjEJ{G(MdSD@&$v^lsPiHd_};6MO`1$5xVcrbvNx|8$#FIy&45qKF3|@>J1~jsjM}E8jeVPQI`Y3X3V9j6Ikbk~j!^IYR zLh#7&=~i{I<;te*Jhtj;zkqqwTZ8Bh{ss62tH30WF59#(00000NkvXXu0mjf*3uOv literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ne.png b/apps/36-blocks/src/assets/images/flags/ne.png new file mode 100644 index 0000000000000000000000000000000000000000..b534b39ff8b08636424bb92ce2a003211c5f627e GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^0YL1^!VDz!Rcf{YDfIxK5ZC|z|33&~v;9`}Cs0<7uAWqZrXIhn9cbJn>-|&({+h-ap`*0n{?v)5S5w<9M=wijYB%mQ1L{ zs)7ZgK}<7vJA#hAx~4Hv$f4zsq=I;Vgjn zJ_~smTe%atmUevRPQ0&jNTe(9^pQ@3)=4ZPQinvigab~n1gTe~DWM4fd#YWA literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/nf.png b/apps/36-blocks/src/assets/images/flags/nf.png new file mode 100644 index 0000000000000000000000000000000000000000..24a862501caaac34b5f61b91e948d11983bc3c2d GIT binary patch literal 460 zcmV;-0WDuz@L2qT*N)J4ghZP z9Nek`&g^2Sr1QLC1W>aL695vHRw87d8+o7^Y=`&2i0~2nqe4KcJ$E8 z=d_#W6(Vd~yN<^SJ;6j|2y{#Z4f1gp-M(#XUjt+1^8UfXWy=UHx3vIVCg!05?V+ AJ^%m! literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ni.png b/apps/36-blocks/src/assets/images/flags/ni.png new file mode 100644 index 0000000000000000000000000000000000000000..f44c209f1b44267102e93fc6af0e7902be585ac9 GIT binary patch literal 360 zcmV-u0hj)XP)J`tths=KyEM|Ni>&=)c?S-Kw#B@a4Aj?8%a^*0|%_m#UlI-?X2% z-Gr&8fU-KB$tH%abF%FDdZU-;qqh;BcKadBtQWQ zP=J35JgGb-ptK`qViePw+>-aCImZB9uGdA!ngJYC zaS7A?Ifb}Un2G0MEnn*}$C)kUT0(LtfI>)h-zVGFJ-Rv`5IL;c_Er>4(NvIu^-r8F zgqVHfoH~q)nff%Q4C-+(xnov1-r?kF_vB9zpa2CZz(a5Gm`i+gDsM&r0000&|)5S5w<9Kp{1nc4i4W?uz#%6_y2_X+x9CBQGq1EHS0v8pDP>WRs2AV7k YXESCAMsxZy0ktuBy85}Sb4q9e0B6G`cK`qY literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/no.png b/apps/36-blocks/src/assets/images/flags/no.png new file mode 100644 index 0000000000000000000000000000000000000000..56062603721dc1eb2bf18158359a539a2d203b82 GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfU!VDy@1{_`lq!a^uLR=XXqIdD=|NsC0jAycA zWNUr@nv&L~ms6^anTP!U_wQc!Y{8eut$>Q7JY5_^JdP&|v@mn3nzFI6sV{YM%xOpr zdAQj)C05_5VHT!wmw82#=ap+%q-zZJxOl#siUG9sX#ur4Y8&8xUSOMs~H2?qr3UpFVQvfOd z|K!3FL6mQ_=gD0F00U4-L_t(o!>!nDd-D(&2H-W?wb2rWiKKh}|Id8LTM0=J`Ly*| z&*SEb8~eI_f0cczsxA#yw@YELsvf1m>Uu8-K7WTIzsrH(?`g=o90dJp@z3IR+D#cMO=cyraNrc}Iog zfo%sGbz*tDVAB9j8jST%8*k7f4xGQ&q z1akBDiUQp+a|oIKe%sRpgxCzahcb0}Pbo7k zN=iN+L=bBaHk-Zoz6(k{$fgrED2<1cm-qZ0>e(aK6l$Moew^CP>u{{K+#!df@~{W}1;TNf1Gh-r#;QDRY8&kIR@zC^ts7zQC`qC-hi3N_h$3b-Xr7mhlQO0ArlNmPd09^&Cj$3U zSUV} z4M-Q4A#>(~xJwsDQ0aV;2kKZDZxY1;?8xeH_&FjXo>=2FWF>+X5*|2SKjK2^{7|q8 zAJ`vpDGRSe(t>nx0ef%EXl#s$;tVQp=@}nyiS-d^Rvslzjl&ekWN}VeDm`K7QzJt9 zBHl?3Qbng9>MH3nUU~4pm--lN&8*>}7gDEVr-(MFAmxL~%@qTKEYaCUks4a9xhl6p zfGp9eupKwkv9_ao&xRN{il8p;^dA-jpo+auy!J1T8Ba(&ck%i4#gjKFUp#v?^TgA4 zz4bhvzdWvLEN~lj#R8x!mH-{GD)!W+!AYzNi~j-HhG8t0_QgK{0000D> zGIfugy#yp{G);%&=I)-V#{b7Gznwe(|NkF6dtP&(^!E9yw$6HsvBAjNLRyeiYMZ~E zJf+yvM*si-fk{L`R2UiU!AlOpFboC2=frmFeB0jtu%L<+?9khQGJ|DVmgQIMWZ1~C zkzxOIUHkX&PBK)H1uW7rM(zTd>2vx7iTau1DV?sMI9lA=0g9|WZe247Bw4&z5>R;D z93&$wo-76!vQ|mWtR<-mh76dxtAVB{YK0aMm4fB3JOI(i4A`7DFU$Y{002ovPDHLk FV1jquZeaib literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/nu.png b/apps/36-blocks/src/assets/images/flags/nu.png new file mode 100644 index 0000000000000000000000000000000000000000..61a86e8d20711957ca4a6741837fd27d813d2c7d GIT binary patch literal 557 zcmV+|0@D47P)4`n{tD!3@UFyS&!99U;!a%$Ph07|NnoFv(rFW>+SP;im>3Txz~-LNDh7{LWs;W5PjE% zTTJA2(CiAf6L{P+m}*|ROx9pg^q}nqKjI2y(D{(b8a$tGAa#d0v6R93OA={fdby+m z9B?+MgV2+cnlv%HUYiaj4zxgtOfcg-!$jsZz?U}LPh;v$XNXH&t=B7@wP*g~Wspm3&SskhIl!sgc7I9qk v3wA^OD}yrk*I&R!bjiky88c?gn19YMh*%=zEw|x~00000NkvXXu0mjfqnH4) literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/nz.png b/apps/36-blocks/src/assets/images/flags/nz.png new file mode 100644 index 0000000000000000000000000000000000000000..90470ccdda15f679ebd479511a85894271ebbf7e GIT binary patch literal 536 zcmV+z0_XjSP)GU zzsm3N_JWbL)=XnSSdUg~o5&C@|Ns9EEOCC1v(-ys@x#jU#?57RqIid{PGgpRjk4i+ zip(QF$d;J13B8Bk*u*aDM{YE{Kci90~<0eR21L*>s?W(H#T5g=5t@9Hgs)65p zmGf2XHa94?-fk)&ND@Fv(nc0$S;%A{UMP8|>-#Ft>w(4nUT6hg#HA59qt!zh#OG5P zn+V{^v+`8~`RbLU{9SBX1xyia1K`B7z3YR`D@TV{q+ruYkW1hHxXj^3pWY0zoOHXt zIz)|=4+j~U#KAQzNBJvUHf-9A8XQv{U#vxTuPI5fKQYLQqbc{@sSa4LLG~j^t9KJZ zW1Q+2P#f<$q=?u^vl6sv)1MI`n&VBW<_^wLKMHCX}r7o++&@`iRC88{66i^6gn`R}(eokH_QuN*6jDl9hGZBM=>B0*qY~^+-5e~B` zXX=RY?nzHb*lg%`z<|q*aq0mP@i`2kiHj8c3|19{DE{PP>@088G~RCf5a>1rPgg&e IbxsLQ0GkqEg#Z8m literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/pa.png b/apps/36-blocks/src/assets/images/flags/pa.png new file mode 100644 index 0000000000000000000000000000000000000000..74b166d523522e2bdcf79bbce1cf7e012f09e1c3 GIT binary patch literal 361 zcmV-v0ha!WP)~sJZj`kQ~&?}2P0SPh>ZF0^4l38$j;jFqNV%g=38x$ae&K;Ilm#-w-k08p~| zh9zQT(OzCFKySF6P4b3YN(OOTp7X>r3|tL+&t`>zoUGP1F$$D>uDh)Fu!6tyD9p1k zWC~L}Nd^B4j1~-r00x!9f|kfa!9WyHU{FUEqUBu!qQlNz$HjG+k>i-XF~Z((I6d4_ z>^Za(Ft8))6;THRdpBu4xgG_I;rv?2L4d&cfo!Y?_J-gKg)Ur5DK-)100000NkvXX Hu0mjfwUMTD literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/pe.png b/apps/36-blocks/src/assets/images/flags/pe.png new file mode 100644 index 0000000000000000000000000000000000000000..c66602561815d4a75f6b60b6ed70ba01f978d7c5 GIT binary patch literal 107 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ#0(@?yR}>gQk(%kA+9$Cl>h(#|1>^lev`y3 zprEX$i(`nz>Er|k=5qlC9tjR?i<=-Yg_DV4Zbp3w*P^z$K!psRu6{1-oD!M<%Sazy literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/pf.png b/apps/36-blocks/src/assets/images/flags/pf.png new file mode 100644 index 0000000000000000000000000000000000000000..00dd2ca834c21e6add182f9b9186c312f72fcdd9 GIT binary patch literal 645 zcmV;00($+4P)f^TWyioDl!orTn~QRCu}vJ)G8*mH+hP#b0Uvv`qe@ zBfcaw*t)yD7%9qec6*n~&Zeifm!rZzP2J@2ow3&Q_4@zEcSvru#({^<*XoU>((Ba1 zq-Ju>ud%!}Lax8w^~#pp#KY>pn3Yvpy2aqFe1N`FUl~fG;myw_RHyCa<^G!x)lewL z0004`Nkl*=~a{5Jj;uq=Rt)vzUDkOUT;(|G(8qUi(nRNR=usvL$#p+$&}V zYrB=DZNLq<0sjZ^V`XW7A)9oV96U*e-lBdq!PFbk0s}bcxtH;(7Fcl1WqNo#4@*1U=Ap9x%UKiK!^Polqwdf zH6b@5{1w?F!=93|Q~(0-DRsH^itJH8lC=Zx^9%&wrS9YzL4EO$W#>oo73lrUjwO}4 z$KW>K=3qX~enbdSXc*ZeKvOq4pW{AQ=H=;7_KQkYe@S4R#L3}t9bUlq9U3xVmtKNH zU(0n4;;`=IBZZH0%0!h8!Lro(sb9{q*;jeiDwK_|F|K#v5GFQ`{J}I6jO|5VkGR9b?KQ{ZyboAEeK+#gGs_b{0WJZ4#o^Q>6sH&uu$tM2UH7TS6;e(i1blf!nL f+khKz1OB9MQ3qeUIX&|C00000NkvXXu0mjfPcTKV literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/pg.png b/apps/36-blocks/src/assets/images/flags/pg.png new file mode 100644 index 0000000000000000000000000000000000000000..dfa0bd56b40a18c00634163ba898dcac2ed82eef GIT binary patch literal 784 zcmV+r1MmEaP)@0001oP)t-s&JiXD z00B(~4kQ8wfC?9>4j;x4Bme*a{LvQw|NlNdKG7T`@SPdiJR$Y67yQl@1Ox=^?Cje| zAo|A@_4W1CCL;?A3)V3rCMG6dUti%}9_@`9t*x!Vz`*jS7~M}G-QC^kf*a;@9r(T$ zARr*;dmPHj%2ZTT^Q-taE~00KlwL_t(o!>yKCa-%R1K$%rS z8z8`7Fkrw;>?HR;-w2Ypyl9WQ%AdUI*NfcI&%aUF0KfhO27({I0|NmFs=We(YHz@h z+Tb%>wYdrCri}?P0$sFm4|_AvL7PCB3>H9JZ4M#KsSVIldlbN=vI5#^w*okqmO!00 zrZ}o_6fGjbvCko+Hb9*=6}ho;Q{Lii1=MOcIh?2Y3kV6e0xGqIFDCFd8atp|n~Ti) z^LPhj*aEoQNws+bCDB>{_j{Q(&Y?6aGqCGq+KZg`RK*8aijGAb7f1Bi?UE%)p6Beg zCu}W3Z^{s5ah##2Zc|!uGSI2KR&tpM9rCs{Dj(wbpy~ECMUKn1Y9?b-(rmxaQuUBm zpD8BmGB5OLZk~Xr8i4ww8FHR{^m{8_O9rdK)($xx8zR!o%kAx+oPpBarebS0)IdCd zvfVCw*skSk;9w2hR#3g$d>d)D5GC;R0DO5dKWQV2a;yN>mxuW|9JJac#gxod)KdlU zax;BmVY;p;x(;c&%}28Kg;g?O{V!Wr_*K4wI_+wf*RVbc;9j+Y>TcuytZ2$>93SsW zSX}OlAk*dzJFDifdqdg#&9}ACMYVp&hl!V}$6<#)em+Ak&oBj+VK`UJTjKP;tpwg} ziIcYUgA`>M^3;}pkak__{G{oCJCLTH-3H#F&<5WKskZCL7`2tRjjy))w(-=~-8Np@ z+S|rQTYuYlXq#>uXKmwcFk3hn<|30_Fi*QT!k O0000h=&tuF)GWAyTyT^Y{lns?#Pp>5`m^q}SnTciKo< z)7njrLFS7#ha>6hSgyk!0?vv0$fS&ZCrSJcA4M_~94a3CN{`5?~u~#caFl%l|1yDXLXn_EC z6)i9X_54B!3=#?O(~tpE-*17fm20XSdMt*{$~Q6(wPs&5RW|gwAO^y!TGIlZtvq8% z0xL~ko(=UW9jr8gQ4zUYIRF@EZN!rl6bsVs#I_stYq{`13fV$Mu2b1K0K-V|B=ZZN zut*JOrPW|NRXFnxD&n&URhGasR-WH0R?_Pa707V9mEETv6FeAz0T-;#qYARa^Cu3r z>%jd6r|8;~cTb2GK%*$RS(N!Bq8-qPO{!x9-}g(j1?HUp3-(8iXbtRJFECo~_7%|q z_;)zWw}|e*N}z*zC*bKvKe^AwfqE6O=(AB^)Gtd` zeKvl>Zk^lLh*ZFK;iNFns4|UtM_@^0o(Aq}B-Jl4A6iD`YXgh`0000fiX~h<8&xx0g>Ks8-T(jp`TF^2j(FFbqX)JUkD~1nz&-UO>7U;#7$7 zuF+Cnp$FTIu9r=Tr<>Z(g4U$nXDUyLw%HY7d?O`prEih}z`NL*Qk~3SoMgHL=I%NxvIdYD$#h z>`r;w)ct;DNQ8WL>otE)T^y=r=*KtResV8+_j=9wD^jEzkGDd1P21>Y7o=O-0_tlH vTX55RA@-%<)SdU8E~;SVE!uD3KLq{&0CXsfZo=&400000NkvXXu0mjfgOknp literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/pl.png b/apps/36-blocks/src/assets/images/flags/pl.png new file mode 100644 index 0000000000000000000000000000000000000000..943a6dd05e0e661c70c437c15732afa00cad4ab6 GIT binary patch literal 94 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfT$P6SuK0db}NU;U@gt*=jvHAc1|N9-Lmw+O| ro-U3d8t0RL@U!zQ_TeZNS-{K?ec>njvBnR|Kxqa~S3j3^P6hkbRlxE-&m9^rS0(7_z=*%WtwIewQIRe>Fe ziZNnsKvZKzKUYtChbkpjFzVD5ovb0}z{)mhb#Zw(lani2bDmjgN7Bd~ilG_w)7dF| zs9RlM_4fH;i5LYtYMZFUb%w1;V3g*#!&GiCH#;$HXk@CmHon3wVwP`~u~0^HRl3Nv zt-zZYTTN|%A?xDgE-5BIiItBjH_BusB5Op9sD#(u)kTDDAdw*D0009INkla1gGB+?@h^`zO5gh z&L%9z8BlP~zkXQ;QcIcum$Vqi7@`ZHy6kadMLm8ylb^Jh=GFa8+Z=aA0rv9^4wKe& zGDOap$NH{IhXwL^=?odat{^f11J>qh{XQ{fn!T1FARKm6 zRHmt6PILJlm(xBpO}m(`OEyr9rL;MqsJ%(9On|euoyD{-2e0`Rc^}yRI!=&Jd1rA7bp(N?ZC)HtimA!LM)fgom8gwK_2gJSF&o4-*LD{a9Gi@-JY9e2h>lR`zG7v+ra&ozAU{I0ZuxUQ9)jyxUkTHrn;bJ(h5r2MlEqC64Tz*OJWeK#X(lQ7m>P->rWyUlAZ|Hq{6Q zfn6;4^~7}>l}iY#&U4 z*N{dAj${#3Dxe{gs*@#`Tm(4UipLcv4KO;C$3R)6!5I&ts#XQUFh_vxk_%KTG7s_A2Ie}T--Flzt+0X9iQK~z}7wOHF0 zf-nq=Q(zM&2wnj7|9?|NL>R-vSj^L2$Z4}KZNdJqp#sp+kxK|%Ph>*id?6D8G$}uX zG%4|A^p#7zU!RRd|OlWy~Y&`%A;!3OstjI$$A!Lzp2?3Rm34tIb6Rwl; zC*c|?O^U)-O0xtr=_#cdpr}2iG`>wmVv{nu@0P;IScuGeIm?Z$SE|M92Fmsno19CH zt&eT2Q>CV1E;F`oR>S%ztyQT{Zhn}5ia3nt3VrWpu47Nl3q%gs;(qs&RgznK?Xdx@oz1EckF-m6mr)i z_ht6vK%Q;L(-(O@WKXc<8JoNXkoOe!CPm)$$lEA+UuJLg?0*hVruZB4*a;3500000 LNkvXXu0mjf&U)Ep literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ps.png b/apps/36-blocks/src/assets/images/flags/ps.png new file mode 100644 index 0000000000000000000000000000000000000000..a7f3bb1fc648c8649d5cd2179d46c1b8ed32a30b GIT binary patch literal 304 zcmV-00nh%4P)9&rn z1l`+hVBbK$Tw%~t1A~F=IdF0IEVwlLcOaeI{`c9?hYdfy)U6^bKvQs&5B4Y&JnV#m zCXpbJn}I~`7&M6lq1*waa^IjyBnaj{Kr;6}V>$KJa79;p661aV0000pN literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/pt.png b/apps/36-blocks/src/assets/images/flags/pt.png new file mode 100644 index 0000000000000000000000000000000000000000..8f9b3dc2509aea30c2ae24995a268e76905d98d2 GIT binary patch literal 893 zcmV-@1A_dCP)H|NH;|0b&5y*8ukc0N>sK`uh9P(E{lN09$;%!Nvfvz5to90NH#1?s<24p8{-_ z0FtQyqPPI>?f?K>0LaY%@)-~FIyc>AP}aNvIDG);=K#TC0Plf+?@mj}QUKmvLDP=_ zzk~qJf(Wd<-sU&~-B1G8rU2B%0Ku;V%yj_MngHuuS96cYgrWf1hXB-O0NHH-*{=Y( ziB!3J0NsLDRfz!KUjW9@=#{F~>}qBF`~ch{0HTXo-g#otp#aQ|RLjBu|Nj8Do&eXJ zeB0vi?6o6-Fc1J>fh@^#uh`hw*v6)J2zPMYafR#Y|NqBCPMExAB6vt<*wN_mo3*vlE~xw= zz~9ChJcDQOUjzkwLQtq!mi@R`OYkJ1V5x{u*>ocr~9y(rk`&llPE+#5)IpkPrCMPmS(;vozG#-mw} z+;C>7A>=9v1FO}lEQ{4@2}(dhI%kHSW_nQq4`B5GLb&W; z;hjF}OI+Y3rK)Xat5vgo^>)Qp+gPoF;V4Ath6|i3cC994MbVs0HnO~tCq_{O7)y8F ziZ4T?P-mJz*lf$@zLK5dGJ3>VW z07wpHBh~@9==pdVV%|EeRfHY%J1@V==C$MFkJn*`%s30X5!nu<_4!bL5ucyMSA957 z2G@IvI=pvTL7roNP49G=7)Ap0QOXi@_q=zxQZcFG*q6KC33YE<1FE<&{{w5gszT7` ztBi;_S| T8glhF00000NkvXXu0mjfx}>Zc literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/pw.png b/apps/36-blocks/src/assets/images/flags/pw.png new file mode 100644 index 0000000000000000000000000000000000000000..9e2d72d885a7a6b6d4dfcc9ac8d98ee7bf176193 GIT binary patch literal 307 zcmV-30nGl1P)) z{{Zj#5ajh6TfL;3*JVSqybz!7i_moZ{sVBvkJ#@gz~(;(ocMRih|20UT3P`#0002K zNklhk{}ll znYlz6h|FCJh%5lM5G+&t!Ro#cQA(A>C>?blEv$zU001RxEtRiYD4GBO002ovPDHLk FV1j;qb2tD1 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/py.png b/apps/36-blocks/src/assets/images/flags/py.png new file mode 100644 index 0000000000000000000000000000000000000000..6fa4a041432d0c8f8b55e381e6fcf207f6c6f074 GIT binary patch literal 287 zcmV+)0pR|LP){|Ns9$YQDR?yW88_TA_2Vudkb%n{29rioKou{Q8;4 zsPpEF^yGQD+{UWWx7Fv-J1#n70001zNklHZx$@%YVPhZo|r4R z@!;VNscfa9Liwf}=SlL)y<*|N__EL>KAC}Go{49hc**X5p!p1*u6{1-oD!MQ(53L1Z(ps*)nR)Ny``vx{? z`)rZ8;OHgB)JJugtk2s!J8bp+0RvEc+HXg*_V^6m4=CsD9@pV9T~NwqjK5|~zoIU5 z+~q5Uq?wsBf3dA%hJgY&00070NklyVkrXZ!{NfXG8j@&WwCATMf*q4o#9vlL4J$Wn~s!%z?)Hr2s3K&_524%&3u^OFBiwM@B*dPrFnw@qP*I@frhqeT4~L2C z7?01W_&Ss7n#PoK_S|HsU}D?G!0z^jZ=BRpqUqOl6c(*6H`R{WBO%qf(ur zM~Louen)zQU2>!DA^JXBtYSCZ0B=Hl7~jDm)Fy z)6rV5{CL_A?;$zlzwic6o_55OLvF#7KyJnRgxrodg4_r11-TdA0QmamO6b4{PL{b7Rh{a`xuo?`GcRTSCXYc#JQAK;{ zbjGgeUH%!Q;eu}tIuZczmH(Py-=5sF`19$eKTI#H>f`OBsv5lyu3WtCHnMXcdz;Vwd8X@pE~2&NE?#K2TVCU4h> zV(RkQrD`n(LWtoAGz6-U*dS0bRK>s~Ap}(ut4ow2Op-*b%c&$`JZXYVRRX`lSduhh zP|~)Uq97$;nWjlt7{o-|vVwy}kZE0sVrwYzHI%k2&ry*pl|)D)2&M^v*g}X>ep!-A zBrFEHDOAl#v05Q_RctjCnx+^SnH6K#lQeV7)4pob-9{E5SoHVj}ZtJ zEmIf=Gb`r@ClCW|LM&Hv-)*G4Tap%GqC8xm4PKqZVzukPXsc{uO}3GC@2^ZHx;i(2 zo&+&wKRP~`Bsj5v?>G%(H9a?F-sds@_#_5*fieV`Wy(4O-Jeu4jxU%;n{U4rFFNB{r;07*qo IM6N<$f@(g-R{#J2 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ru.png b/apps/36-blocks/src/assets/images/flags/ru.png new file mode 100644 index 0000000000000000000000000000000000000000..6139dbc947759740fd8a78c24c4175ef6af6c9e8 GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*m6n}tEi0f5tIR?vR|NsB*Gw@!u z_u<1j<-b5FO-~oc5Rc=@AxR2+28KOaGNBd~BAWze7f7xmKa*eZA zKVhqO+nk)Wyn&#?_Ntj@4$m%6CG4AUpu$;%4PgLno+xz_dA+Qo}0004bsN1ECUlZPl5PHDpfhEiE37*L6VaG8EX#YhN7?~RQpamv6~SSgzl zsc03g87QtQP-c~#%W;CNCY&-X$rt%q>n5f0*n9O6t0xk;s;R~HO50vIb$4G!g6jh0 zf(T9AMq8uJr{qg$DeV=ybr(+AUM0lL+axksDl^!dxSlB2tt<#on1L@G%aVDo=c($U z?p;+T=iSNIaHY)DqPq8r7f$8mWz%j;)(a7sIkjbO+k!6?JRwS!JU32>qzi0v)gyuK zc47A3KVMI)I$0i82V2=ooN{f@oMC0f4W&;lNsGQ55K04Wa#aTlk5fEk$?6i2y7kGX zw>&P!oe(~@XjiCIBbLB1*9S2I3m^1&MhsT0Pir~(vXYS+BFLoiQx1Pv03zbI2)1~= zUVmc){!OLtsSgo({2aUQJv7zV7ycg)0b%fZyOV07*qoM6N<$ Ef{+>cc>n+a literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/sb.png b/apps/36-blocks/src/assets/images/flags/sb.png new file mode 100644 index 0000000000000000000000000000000000000000..31a9f1544d39827c91a9f1478335499e9da4744a GIT binary patch literal 457 zcmV;)0XF`LP)?>}?(BJYyf6O>{ z$$h5WWtG+0kcsvH00BiwL_t(Y$F0=cj)Wi#08k3M>kQ?t|NpHEh$ze@Glf1F5pzOI zQ^uyn@BJ2Ie;1+M3xdcU;HKJLwGp|$pM7nx-A6;@mL=uqAO_Y$ZJ5?BP`C^-VE`mQ z|KJk92okr0EP+kN0E)(y6H3dSJ^!+fTSwz|kf(Gr7;@q4@$GxAq+CNQ#uzo(2QYY# z=zSRB8j$DqaeRd9QdS?`?mMmnC88YTDwx~Y8qN)`OA2>@cCAc)td__fpziwEX(E?F zuQY-_C)TDkpjMv3?I&DQyQo^XG%EmB5?4~zvHhBi0W^&(pmYW=7c0;>N#n|Jh{xG3 zCG)YInv=M*v9Fyc&egYEKW!Le)Y^RjQn)uDje7}FxfdXvdkT(lPrxzm0UYHzaGYzv z8QcY&!&Pt=SHO8(24`{+oXbUUE?2;L+_L-w6s$L{=Fyz600000NkvXXu0mjf>*LY4 literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/sc.png b/apps/36-blocks/src/assets/images/flags/sc.png new file mode 100644 index 0000000000000000000000000000000000000000..88717b79871bd10487e3883a30e4845df2c0c714 GIT binary patch literal 492 zcmVjMC@YrqQ?~j7}(yQUrW9k$O?Fj(y~+L0e~p zK>z>&K1oDDR7l6I&)ZhQFc5{|5iE&D7!*(xwaWWHB&BI$PLoVW_Qk&Z*81UroVlmA zTxfDYdPs3kk6H`B?F->OZ?p(Bg4`O2lH3YN1UGUkpb_QLAj)z{uo%q9B|#(1r9hPC z5?~>inM;61oLdG_o~w1Yhh{K8x7+WOf>tmycQI-z2T_#kv>Z%=S-F9hgJy1StYsk1 z%gwYDjDlOaB`pOFJD1QB5Sh8O7K1@>CAV8uv=}t)+-`NJ8iPET%4KLF=!46-JWZ(+ zq`{?Jj&?YG9@pPJKpb4iZEBu^{(4bxmRr{X3jD(0B)6iC)EC550Aij?X@|Ghi6Z8M z!`!0gs2-|w!GF2AHc%hyci_zi``kpEMLBQ?o^nG?KsnIZT(60#3B+rz)&5D@ZO@xQ iy9s6Y^LxA%HSPiyr&RFbSch@|0000XPE}EY^|GVkh!*gM`RZuacx!0G?<3RF|rM)H1?;!w%}{` z8w_eV!=T!;cfj`SU9dI#e;}MpABBE4@WZA*y|F(;R)fhrw)zJe`Rm4~EvdO%I3;;#d zuG5}#7E8e#kpNLrAMrg{y=abPCU8lz+3Nf2yr-k(2y{tB`3n|RN7NTES6<={jCXi% zC_eB_S(5s*gUz|x2{@l{xw9-1eameFhDoY1W=TEW&MBTi%97PmBn9`2lfO-`s}LcE zrKI&M&ZA`Q`qjI&xWwYx;08Ci!3}P3gMS$O0d2)WYbl|WBLDyZ07*qoM6N<$g2>CN AV*mgE literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/sh.png b/apps/36-blocks/src/assets/images/flags/sh.png new file mode 100644 index 0000000000000000000000000000000000000000..067cae9ea05fb663f448bf34808389ce7e859a70 GIT binary patch literal 845 zcmV-T1G4;yP)F~ z5HA1!|MJjD03c^US&vm~oAJZT)=XmU@bwKWaSADJa)Yeq#zkLzx_OGQ;H$W7b%fST zV}6da(?3_h&(y4$M@Ch6U2>r3z{=rxiiv_xZfSDQ+udMpe)QAXfRMCwhOJ0olL8`X zElP>V)!EfbV7i!ytAuiEa(4Ch`Jt}GlcK%ULRxNXOpKbc>&iwMHF<`AP@bQqdwX(w zd0(`Uf3b>qrGa$m?DFQh#1JZCg?>;%PFZDVR8CujetMvjfrZ_@L8_{(ysevpeU{tf z<6CEahkS&ijWua-g@%cCX?c&blZSG9fPsd5Y=4|(UUJ5Rp0=f9FhFs&sCkxxGS;|4 z^WWr*gK3$NYQ(p$bZ=E`dzO8JeO+mbh;%7+fs@{Fg5Pt5<+j4sPGq0phPnU%0oF-G zK~zY`?bT^hfA12MGnOv}7F?Xdg4@4Np0UuXq&Sfz$+zcl0Pj5{#+ z%sT7>a5*7#2RP8l0T~>0bWd=Bu%B@`f!(GUo%C|nAmQ~qX0}CWcfbH2qIPb9y z0&bijO`wV6!EfTsv+RNca|Zd*Awvcj8kid~O5~goeU0zQ8sJ`_jR_ zY=ex={vn9;D1m5kd8HJ@l~$G)(cf}9BZ@NWxyxp* z?*Yqe?fDa6V@=o;4$80l$NPdXL4qV_@e1HIeU`+JPE$KI;qggTWf_Cu@5!}vYBO{c zIygC|0-}q0I(2wdQ7dYB^=y{H43qV0{qT9)agx{;R}lpeDAihON8H;}6s180l&k4` zX>J35iZuQ)ZY|y1ip3@;r92%EBy+JX34^&LB@iG@ib+zDnunV$<|hEv5CX%74I8X4 XOH()lA9q7U00000NkvXXu0mjf?0=WX literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/si.png b/apps/36-blocks/src/assets/images/flags/si.png new file mode 100644 index 0000000000000000000000000000000000000000..8a27e2ff772404b3c7724729cf1e84db3528ea8c GIT binary patch literal 313 zcmV-90mlA`P)q3x}I<9qeES{{wsh;g~~%n9SI900000 LNkvXXu0mjfX!wNb literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/sj.png b/apps/36-blocks/src/assets/images/flags/sj.png new file mode 100644 index 0000000000000000000000000000000000000000..56062603721dc1eb2bf18158359a539a2d203b82 GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfU!VDy@1{_`lq!a^uLR=XXqIdD=|NsC0jAycA zWNUr@nv&L~ms6^anTP!U_wQc!Y{8eut$>Q7JY5_^JdP&|v@mn3nzFI6sV{YM%xOpr zdAQb(O^LE;i4`*Y$FD`^Lzts>d2x zsAG=9Fln&(p{3Zaz2%gjNO!h?o5veUnUpV9gq+6nVQ26^NB{i%$8w0(;P2(q+u$B8 z_n4fwH&VbRKK|+Irz=d_6Qgke00B%%L_t(o!|l|`j)FiGK+$WJ@X%rwoIr8b|Np{X z2;GQo7!rHI-S85~2}PCS3>+gkf+P5S@ILv_y*pTh_J_hAZ<&CgH!_qZch+^`TTe611do4KTvBxbq6;JF!e)V0JZr)psN67wD(-Hr;X~j zt$1VoWu3%(=M;poxx=J30x+fLGi19ge*z2a`b%Z4!R1?H^@XpGPs@F?nwiT zeI6p)*;b^yJn-WlpyY?<1BYDtfYN-QxZM|g2a^WiCvCx5qia;Z9bIQF!=jO{iIJvd z);nnJPvuWzecCes2&|%5B#u@v5NO%UJYQ-C0|BLAP_SzwID#Yi9qikUr literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/sl.png b/apps/36-blocks/src/assets/images/flags/sl.png new file mode 100644 index 0000000000000000000000000000000000000000..90341302092cf9e9bc9cd33b972c1c25f06ffca7 GIT binary patch literal 127 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*m6n}tEh^yRID~6(D|Ns9FJD%+@ z?dnwdOD}*@+MX_sAs)w*6C_v{CulGwD={_;O-u-RxZ;rG(hIE~2NXP1Btk7#6⪻ ZFfgUg68v<*T^y*5!PC{xWt~$(698u8CB^^% literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/sm.png b/apps/36-blocks/src/assets/images/flags/sm.png new file mode 100644 index 0000000000000000000000000000000000000000..04afc0ae640d133c1f153f624e04636d774d98e6 GIT binary patch literal 1130 zcmV-w1eN=VP)@0003RP)t-s|NsB? z_VzVeU7L3vRC7q4rKDnNZeF(J{rvokxYDA0AycHzFGMVvaUe!rL4$EWa#t2-a(3|U z>N{6GdSxs}WI%$f#n;!?ud%XtT^M?lqbNs3G)Ff|X+m9mPQ#EXZeJsRVHSdC8dUcDKTeIP4kX?XI(n>0}Dw+K~z}7?b5}P<5&;{P>Y!?1`8~MEHg7R z7gKlt|8LB0R#OpOvNjXpyMFJ)&5TSW?z!jxlVmbp5BNQfSH!=*Vs5C_;%%7xm5&bu zfTTM1y|J1EfLO}C9(XStk3%mLzQ#}!Ka%~&ld9|L>5(IA`0e5{&mB23pC`E^mp{ia zvI;?Y$4jR@Cl5ht982W#nM{WFcs`To;yG%G8SuQ$4@MFm&)ujV#4rp4d8b4oaijUr zOW@DE9*!7h6zcplonriwFqX5klh5vAZ;`%*0rB?cm{0`WODJ{43U zNMB;N)x#?ip(4^Qzf>#<>J!AeqYP1^vnGf>I_eU@(66|?!>H|%>*Of_II1*RQB zK&RJ>K%nT9aMD4AX6aP!=OEUEE40X(p0f~!hJwBm!q8Ya>AFdmXqNgpI4cHbX=Scl zl3NSLRajov6N4k&fHy5Lz#=rP%PFw*K?iB)y)2aBHoGlfoPMKi!fmS&1;mOhTV1UJ z*O%sVd*14{=92G%uxMM2StO9kfnZ9mh-n6Hb-VLc*JfO?QKGFnhD8G_u)TUI$zWf% zTitHU*83uCmT0(5MFX)}u~>9VPt}||u;<;@zy+(->eHWGE-Hv&Ihqc*oPfUQFswff z(SS2WbB1BjK`@JD&%K_8)Q+{9c0!62*eKipVnvE-B71EiEYb4>d@8EytA3oZl*&C~VZvX%Q07*qoM6N<$g4NCsi~s-t literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/sn.png b/apps/36-blocks/src/assets/images/flags/sn.png new file mode 100644 index 0000000000000000000000000000000000000000..4983ef78478b0064885411830282bb2ee4c7357b GIT binary patch literal 241 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2)*RDe&2>)-cI46XK$rIkZgIJ{2M zJ#@`cZle907mfv+9qM;EOgQLZHP`-(?t)UF`VLPQ#}JR>$pS8HY&;$fuAGtvJz6rM z7BM25*aTKiSlsB*n#1X$#Ur8`l(?8hkn5(iv$OEg1{X#}VR5I3AeOahzAT1Em^gM% zlssafe$1HrpqTK&4S@jxlQdc#+`9x9PY5+I^)YDRXq|J3^^LT;z`_Z{mq1-ZN( m-*L;IZC%XeE}9h1!Ej;TVuw7Hd?}!t7(8A5T-G@yGywo|t4e|Z literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/so.png b/apps/36-blocks/src/assets/images/flags/so.png new file mode 100644 index 0000000000000000000000000000000000000000..bfa58d00b20924510d3928e644a624b1a509433c GIT binary patch literal 264 zcmV+j0r&oiP) zKd!3vuNI@;7>w6wQ-isE15G3nQ!Qq^g3TNBE!{L?>^XzMaK8^h@KeS?Cn}*c+(KtP zflie{r%0hJ|A(@S_vY#B$Q|IFAJAqby(cNU9xCUx9kvfE#6Tyx7%LkV`?vrA0IEquK~zY` zV-O?~FpMgsvqEDc0fQ2eU?3H`5D6G40UQlPDr7GpQsK4)A{Dkq5UH>uX`!J&BArmsghD_R!62FjQJ6u{?!BcTb>SNbyK)am;Q=BPa)K02ASR|k z3WAXNwe$F!;|WN5`&00000NkvXXu0mjf)V}Mg+9$8N1wa%aI$K&H$Hd0IS0Qu--1e%K(M307P30rriLO zRmL(vrbk==X^a4*qW~r|02Uqqo`&b)E=a_*rPXIigs_WRb`rbtWz+ZV`u^7^Ge3*D zYHyR1;Q9or92x)s0RBltK~zY`t<>2Tf*=$H&>O{I&Z%i;bN&A>W~NJoUV?L8^u@in z2awWc1r3p`z#vhcfkC2e4F-u|RZgHpRY`L&Rg#{x27^RZ0|qJ1z+iubGBD^_CH>6x zwsDQlB=hU#g#g8(%5v=#eS!SAnEO$9f&uTAP0Hup3lzLHHzz+kf=SD#w9C2wu5$cN zb)zSgxyn=FHgYg{fqf=jK{bGhbrDO~P3c!CtQ9(MN}sOBj$FWwjTE10mA)r_2V2SU z3A}oGFh2+Q?`ujFGWXbAd|(U+%KeT3K^b{+2Iy6u4SJSmg5KpBAYxh#j8WVd#FRIK fpzfWc0Nb+w7ZU)bdlPC`0QbrOig5rgCICg2 zx&iQB`wH}GWNz^CGlbW4nG+R?uiZwA;#r9my}zyJUM07*qoM6N<$g16a+(*OVf literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/sv.png b/apps/36-blocks/src/assets/images/flags/sv.png new file mode 100644 index 0000000000000000000000000000000000000000..82eb019ff7c8845500ad57117677107661c79189 GIT binary patch literal 479 zcmV<50U-W~P)6|NQ^^=>SKo|Niy=`Q2u@W&iZX#N@rV&(MU#e@C0o=ztjhgUjOW#j>3pBr7=UNL$cYg(B0PA?$n30iSp~TTBvhDcEe4fnrD&E z*wd^1>)_tt-cWn7%Gc-9&5n1P&j6A>N}tlA)S!u`z^T}&n#G}!uGrPpzO2u#N`ZK# zvw!;K)S0!~_2i|ZxsWeryI6&jAz`o7z;*k_x>+ltFr)c3Z3?Wh(+Qnda*kp+#2}I*g_c-o7hNsKA zYc&8G6DKdG%Cmw&)}KR+g{uBIuBtfBZ*9*60C5_gXS4b%dlf(o8TVS-Xi}DwsM$6k zrp$=zJI-hns+NFRK#48oUw3}fY5*-CC+^a=J1$7!&*#A2-Pu=<^$F0R1~vGf;1gKD VPZs!^QoH~F002ovPDHLkV1lTq`Skz* literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/sx.png b/apps/36-blocks/src/assets/images/flags/sx.png new file mode 100644 index 0000000000000000000000000000000000000000..7c170b3c667fbc8d6bbf6ab3ea96eef0e19c83ad GIT binary patch literal 831 zcmV-F1Hk-=P))=BK5< z*2Yyt?Ck6G(G;-9-0aqACP|R*;Fq%O??w5#XG!M`6L z;J_y9(o*5dN`aQZv}s<*KR<-9&#ZWM(OogvbaYW}r@zbJ+=hMSrl7jIx|f%#e25#p z6%{#Inj1iiMPs1fmW!r&K) z`66`?8vT+CA}}R`2+7Pof-xyvpnS(GbEGq=T>=Wnb-hb!i1& zkVCI6s7xd9_yYYz)0nDJ>OnNUT;%VsEv9;dQ)e`zRAb-yu!Qncc2fPk!bjX@_$R_N z8ZRheD)X7@4+(u8JL&Y~Xt;^reDgjVtf8=ud#Lqs7Z6S3QaAE!vBR*!*#*-?*;1H(J{sU()KG!mSVzdAN002ov JPDHLkV1koWp%efB literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/sy.png b/apps/36-blocks/src/assets/images/flags/sy.png new file mode 100644 index 0000000000000000000000000000000000000000..26c2935b06f0f610af333ae7523aa643bed42af5 GIT binary patch literal 253 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*mlx~1ei0l9V{~4-mfxL5qY7Vn= z9UL64+xoreo&M|bv+vh#{r&vq)yzfr67%0KU;m`Kz1K^<1gNyz)5S5w<9M=wijYB% zmQ1L{43S*|oDvxv7U~a@6&b%V)##`knAXtW%Aytx6lhE;uF;WrV9M6aeIxS30$!DA zjoqz0a?;YbAEqf*-@0MJXwJ=PA}t;LAWgCH?6afSc0_t8u~}$hLde4vhYl_gV7QuaUgO*~u5O^S7(8A5T-G@yGywo+k6Wk! literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/sz.png b/apps/36-blocks/src/assets/images/flags/sz.png new file mode 100644 index 0000000000000000000000000000000000000000..993ccfa4618ad0d1f1f3a6495b312bb14ee16f57 GIT binary patch literal 809 zcmV+^1J?YBP)43aSeWtqKZ4LPA1Pk?QE^JzJz7ASGBnaNxfHg@lAmNP)Cd1Vh5NK7P7Lkk{=?mI|eQ5Bw*A-#XS`0Q}Lh22V+rB}tYC9Z6!d zS*)e$ua~LV0aTp%007$(xGdu>lfH_xRo@0c6G~a>^b1kSo(gst;vJX>XIU?w4pN!{ zpke|8vJ0)6D9pDXib|@)7QA>nNH|gjd6Sq-t39Hay|1K)MHv4qbx=7E_yqD0xi3nS zh?do^B@!%s^)OHIB(Ja{G*t=-g)xVl8k!i6K6mvA643OtD`TtleS0@Tc|1Cc^8iwH z#fe}59R+~MHWW9SXr`m+JjTOlbl4bHl1?9mw;h*y4M7DowLEq?Fm3^by;_#N}{lZZ@0YQEPBZOho$m- zIUJ5IiBbSD#gLsH;mWxwb%Z%L#pR}y5hhiH1Y=D1SKZEFfC;5#MNY)BhFVnAP`jvM zRvrvE4`Ol!-1B}T^}1(Y0_Sa)D|6+5^2Bg()jA^o0BOC>ukkVEs7N_d`FLpe;rXCP zidyY&Ouc|Y$m#`8Z5k4yrXQ$rH$+MZrZ<{LW`wY2;Nqg?acng1aw`;%5_bEduARR=HY2#pHoiCiQUPYa`eTujNe%Y&y>t&i-o^luNR%XdLMq5 nJO6X|5C6XUpY|Tu1E0_z#U@G_`9=F700000NkvXXu0mjf-d$_D literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/tc.png b/apps/36-blocks/src/assets/images/flags/tc.png new file mode 100644 index 0000000000000000000000000000000000000000..0427a2d02e1065cd548d9d8487272e449aa97fe1 GIT binary patch literal 775 zcmV+i1Ni)jP){H=K4w;$A;46JAc4Kr}!a(|z$ z#!6>5vUpkEy!OX=7k zTf~t8Fu;lECt>93kQ{=)=0fC(2d?~@oAPpbktzzs5+Q95eDm%Wude+Gu|YDD0XUM_ zU?yh%IaocK4&l2kdmZQ6vCio$ux1O2-~WZTFZUckoyhS_mWyP6!; z*o%augv{K0`lGRP`N7EQW<+DV;KFhXEXTHAH&po>PW=4zM4udtj)LpU$Ix}`vkfO) zA;)ot!(n-}%7fuY8u{3dbyMT9+@Q_l6L#or}A=H&bKvb^n z)26QP*UBiND0Q|WMpE?+#EPa>67*R1_72b_lT7kA@(!&kI_fNK=S=_r002ovPDHLk FV1gW6gbe@y literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/td.png b/apps/36-blocks/src/assets/images/flags/td.png new file mode 100644 index 0000000000000000000000000000000000000000..db0dab0862ccbce934522527c9f176f6e3666489 GIT binary patch literal 122 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*m6n}tEi0d&P0|vE}f2SG3Vx4aK zC>+hQ5CKZ5dAc};cpOg_aA9-v@^ENnWbM(C3AI>N5b|)vp}^L~T<)Slj*1K~7f#`r T-KCHW)WP8C>gTe~DWM4fez+g( literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/tf.png b/apps/36-blocks/src/assets/images/flags/tf.png new file mode 100644 index 0000000000000000000000000000000000000000..34920dca8bc07a4e44f30dee8ca16dc6b484d848 GIT binary patch literal 359 zcmV-t0hs=YP)w;N9*GBfnT%^||vY1@- zWU?d|?QBdseX?W{gBhLdoWiV_MBlH-RWOKTgpkY#=X_pxEdfTd3vex|+P=w}gzrJa zIDxX;5I)pz2p?rag(aa=~0QFgHjKJX^_yv;&4Ur?y2v7h3002ovPDHLk FV1fger-c9j literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/tg.png b/apps/36-blocks/src/assets/images/flags/tg.png new file mode 100644 index 0000000000000000000000000000000000000000..e7a8e8e716b428fe1818b23856d7595aca188e0a GIT binary patch literal 314 zcmV-A0mc4_P)I0fSf1)|Np9rA&o6N{mlT~OJ~$BN#Rc-{>=dCg_!!^cHv6}-(wB9i5iPl91Q zTUy_p1Z~$R+z?Ms9*e`~dA119@;bXmyp%b=fDQ%nwipGv>2%X683cNgFteY{d@1c| zlEur%7sO-ka*Xd!k|AKHKPd$dciruaoARijwF)Zu6JQO_Xxcya0s{3GdFPbESpWb4 M07*qoM6N<$g2#xB#Q*>R literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/th.png b/apps/36-blocks/src/assets/images/flags/th.png new file mode 100644 index 0000000000000000000000000000000000000000..dc580e44b5082fda4662f4e55dfa194b5df580f3 GIT binary patch literal 137 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*m6n}tEi0e{GLtQPeFJFIbvJc+0 zXULN^k!wVpbfx*+&&t;ucLK6UuN+~Y@ literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/tj.png b/apps/36-blocks/src/assets/images/flags/tj.png new file mode 100644 index 0000000000000000000000000000000000000000..3ca544a7fe6dd353a42b1cdd69da64fd749683a9 GIT binary patch literal 264 zcmV+j0r&oiP)!EVO_r0I?rVK-B;}`(=yb zqCw4Pxt>4I_koW?lUKp_f{Nt3!AokZ;dt+Y0BQ}S9|gC1r;P)Ej zRZ4kuH&j|j2`Fgw$^;%YUH{PlgL^YWPEKZKK((G85-nnkfiGQPLvL+6;k*pLq#Cc8 zAu2ssq>?4asutC=5uJ@Fm53|p!3j7=Quz7%@y7-lH+WKLnX9(VAUu1Jp1vwYg3YcJ zc!{q^UX!YpBGK37#LV34?ejcUjM&}h;pFY<6h@8!00DJLL_t&-8STO8a+@#|2GCC+ z=}KlXU}2H~-c6FW@Be(2(oCkV*+l)PGd&0YUEqanFzWifK61>(SJ?|DywwNH6sv|5 zrtI1)X5mT@Wq6o0BP+#&=q)*d;~`{6zeMox4MPG!pA=?0yuRiUF9vZPxKL)zo9#gvtxKcx5zGNL;Q%dH!_7hx%R zralc83LEODu|#ZWNP-3QGY!h%FQG9So_J29a`=&3nxNr>H8iEflonqSnt@?lyT>P4 z(i|Dbn9FhMX P00000NkvXXu0mjfuT=rD literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/tl.png b/apps/36-blocks/src/assets/images/flags/tl.png new file mode 100644 index 0000000000000000000000000000000000000000..76a6eaa7e81c01a7c01b91bfb7ec1f4a5c61637f GIT binary patch literal 382 zcmV-^0fGLBP)5U0j68yC>=F{^3bFIaA8?DEORkEH#LgpE#903rjfQHs0+t(se?MP~*S>Q4P`rQIR4qH41Hw){4~> zXyNi!igj!-nP`Wz4>qjgetJ;k%i(X=7yE)`j{x$JVvkYwpeL^)>}83)&XE^R_DalN c+S$JqZxcaH%URfwasU7T07*qoM6N<$f>yw$sQ>@~ literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/tm.png b/apps/36-blocks/src/assets/images/flags/tm.png new file mode 100644 index 0000000000000000000000000000000000000000..aa768b815cbcabc755649acfaf5c4806f422ab17 GIT binary patch literal 1379 zcmV-p1)TbcP)jF0F7e7?4l4YcRs7b)9H0 zo;)$3cP}(&I#NqFPHH%&S~Jx!FPczIzf^KLNU8vFEV;Y zyoiipOf_+2SFTZ2rD#oSggjYhOiihGj>)LTf1TFr_Xr*k&zgTtlQqI;&b;XntyhX+3{nG7o$@A(K`+p=qDd zwt2sq_x$;|dVYb8eLIC-rL?NGhHQmzWS~zkyM!*5Z*bSi%EgvIWPxg^flsW2EdWX{ z+eS5ctOYax00VbPL_t(o!>yL*Q{qq*#S=()kU&fb5PI*3AP5M8AR-F5*n4+fd#~Gj zo!LKnvx~UpTb6r2WHL81zd7f&KB%8~f>+X?%?AHQR0Vmg;}ku(F=Ns;->f$!B9mTGnnq>wk)=RG4Z*GFR!^xp+T% zId=8IS6>=PJoH7-)&_=U`lS+;y^|!#UN4)1O*BA++HI#=l}V|^mlvB7f#yEKg<2(h z@~Hd4a@vXg(x&cGOB|ct(!R**>#HDgoNCRXRx5(q*1NP4EmP#ce9<#P6^Xuze(+as zb5kW&8`v*#m&bh`$HJP0TF`ksGo=W$f_ z^u+%DxRLHkJ0${#9B8oj_GZS&`X&s2BqjA+t4(*ke4ddUJ>z&5A;rXm451kD$BF$k zrPZdK(hrB(7%}oYDMf$-ws+8wBpI5fQF4+3II)!uGD`UlX3gf2Vp1OiP&icx>Ea4H7@Mj821l&tDe;Dc@n0NCTT5JHm^ zgmPKuh>im&BzEXxkQ?Isbx&C~2>>)I#5oKwG=q}!j{yE{#5;v(Cq@7JPU$Qus1WB1 zn#TwxDFivC(P-o&;se*qItS`xQ|AG$VX5CS>@E(WaOxZj-qs@#3{03d&g4d1LsBEg$GzXFF?Lmp@RoQ-ZUERVzNG9LT!5M-Boj3on# z$8$N29nCukh@^BsBqc$CB&B2^%chIvhl2nM`1h8+oZSurM7T!7^YQrZ ll;|Am@b+_xJz&{Qv*|?^a{z3LNYj+W^YB=m-lK3@gC0003+Nkl#00h{wS*+`fv%obA8~l>xn#5&7E%DOf_e<+kvp^ z;?uNtYXBxS>mu}Cm0!5TX@Ka}s)yLAS_6^W7-3YS1bkE_V3@frKvJ6?hAio{z>pVi z1$s5f0VY)=)u1khEiD8HYT|(;$#WSbFF9^rEezl#8K5|$%J9{xMFO&-B2&1AKfCV9neyg#Z8m07*qo IM6N<$g2_AH-~a#s literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/to.png b/apps/36-blocks/src/assets/images/flags/to.png new file mode 100644 index 0000000000000000000000000000000000000000..bf01d8b49aaf91fe6d1859f19ac20f6cb6f5433d GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^0YI$5!VDy5`z06wDTx4|5Z8kY4FCWCe^6h4Ej;|| zl`E&Uw0^yM^>pggz45O&fodE*T^vI!PA3bvFdyQvU|7l3J>^PAu*87_Mmt2iv^5P4 z474>>g@QD=Qmy%tT3xEsG>-6Sp6uz;tP$yH3Um-+V2HRSF?-40HFto9F?hQAxvX*%E^w3`GHvMHUga|NqmDU|ZW# zMMsh6FNe5Y~{MVYs{k&Iuw{v~7CIfVY%ZZ0`j)yaJmBITE{-%K6 zWi$d$8`P|UxPr~Y=Y*Z!y;C-^4?D#h8Fz{+U3&(0>uqTd6XaeFNNv4``*WzOs;YVb XmL>}Nul~ng00000NkvXXu0mjf=D4xb literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/tt.png b/apps/36-blocks/src/assets/images/flags/tt.png new file mode 100644 index 0000000000000000000000000000000000000000..e7904e7b29efa67a76b28f66e8338b7430414b8a GIT binary patch literal 653 zcmV;80&@L{P){$3+S)Ft?b7f6 zg!6-#g_GXnzOCP95krzH zK}i$1SjS#|&p!5FP^v53Pu6EYz^s*^)GZ`mmiPlSN>I8Nn5QKkGq}|{&~xl$&ao}9 zD-3*&kDV`K*rhs9WK%k_Vh`Cy3Ch`%6{c5$Qnj9}Xq2FIH^}U)cp7+hI&jE}A3H0O zpsa9%(gP1mJl#Wz!2=FiVI6xBQVc#&(!_D>fUNL>Qf=WrzZm?W)Gd^DRvefphBu&e z4H&x^juXWYy?uX0R=fwL$o|WUiDH-lyR?LhD=P{eD003+Y!yTP0D2`j6vHaG7^Xq# zUXaA)c?T*q!JB`CddAA5IJg02ynFZWPxl%RJ+nnDQ%kH}z9>ab!62Lp>? z4k&A1F;q&>TMYkX#XK;e7-oXQh;$tL&xo80z9|MJIE+YFF$^PeJ~&Yf8qhT&qu(P^ n0}dnd;vSJYa2Sz}Vle$LeW_%A2)G0q00000NkvXXu0mjfH&Z0| literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/tv.png b/apps/36-blocks/src/assets/images/flags/tv.png new file mode 100644 index 0000000000000000000000000000000000000000..03d96a3f7ae8ec27b292022a5e816c16d7715f79 GIT binary patch literal 704 zcmV;x0zdtUP)a)Gt)E_&ms^-=f;dhAc@b!L0WUhP7HCX7h%%n>#q_#AcEjBX<0}K6*wz02;t$jT zZP-Tn2`(uImQ-637m;yxGHR$l-Gb!M15hrFt259BFEV-o(q$p~n*glU6@Ffn39+Mu z88Ebq+tM~y%)OEW>D7~7P5-b>l7g?ch#@ z1NOFO$i{i7!{z=) zC5Jcu;t(J%rXnIb@IxWud!A1UV&XyAv7m&gFJLLwNt=zjnPfSe^y0h@b#1npd@MIV z%9}}h@qa1~!&r20*r|KD`yAlL?wT(s_ituo0OmudQwbsvEfL0gMt{1%BLJ&`>-JJy mv?XgsLZ~0x(L~u8|F0hlkuaJi`>A^X0000q6`hEP&A-3on3&Yv-SMWT+6D%eMnM`ZhMJCnuz|wBXIn z>Uw&|fB{RAn+Yud0084jL_t(o!|j#Jj>8}fMHAP?m}f}(|KD2Dp(C}csP<+w9La*P zIEt?VWh7ek^$gsKnCEQ)pW|%^Op4>njl#sM7SLEN8 zu^MDZ!M}t)kX}eT_+jkpPFf*xKyqG65$_2DlU8^Za6(KBG!B$=7!gv064S?6e}6fg zlfrz?kkxI|>o~^7>Itaz-@SS|;r(`vWipveCX>m;oCmU93O7dmMYR9`002ovPDHLk FV1k>+q(J}x literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/tz.png b/apps/36-blocks/src/assets/images/flags/tz.png new file mode 100644 index 0000000000000000000000000000000000000000..1e2d3a79751d8921fbdf84aceb0573ebdc3280f6 GIT binary patch literal 442 zcmV;r0Y(0aP)<429va zS*y6CxV-;+N{5OlO`D`Sw`b;`57zQ+S1|1Ou=9buciy|+p|(0f&nvA`Fw7GNC!W;_ zqC8nJ!V?8!JV7wdv$h3Qp1n7q%Ik-l!)uZ}PLRZd6{zx>R|gzkmEvuT0S2$Ycy-}< zh89fnst=DAWbi0K8gDo92tgX})EQck%S#2>ym(N+iv_P20WT7i@zCJNYuG$2=y@&1 zD=}U;nC1b-3kGv|fgp{yM|jI%ChtE;h4&3Ub$C-yi|2!SyfHZP zdJUcndfpw&)dvR81yj5uhv$M6-pv?JP?6_?syr7|<+-3L4-X1?SWwJEf^uFkn8OPN kA33~5u+HQyg1Nk5Z@7hhE~IT>;{X5v07*qoM6N<$f*7N_>i_@% literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ua.png b/apps/36-blocks/src/assets/images/flags/ua.png new file mode 100644 index 0000000000000000000000000000000000000000..0387404089c8aa16c9e63a3042d824e96f242814 GIT binary patch literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ#0(@?yR}>gQk(%kA+8M3yZ>KhXqXY}_`ARa zC@Age;uvCaIypgtbuoi}L@TR7OA_Paro~MK3=I4XJ3sb(*|h_xjKR~@&t;ucLK6Th C869%~ literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ug.png b/apps/36-blocks/src/assets/images/flags/ug.png new file mode 100644 index 0000000000000000000000000000000000000000..ae1033efcdf36552eabd1ff18b0db08de66eaf06 GIT binary patch literal 452 zcmV;#0XzPQP)KIrlzLH$H&{-+wPE%7#JAfrdyYnm%APw z*-4-TV_3MZU=sQ>@~{z*hZR9M69mbZ4pFc1VWJ_i{90p=u8 zfeH@)|A8*ln|uNa6__6LZqe+jO=MIOCgB6Z*T|@k$RuGBJ|cXJj9NpM=cn&3&r~GZ zTAzPUHFX=u*9lVmj9ZW{hA#(ZGtL0y;l4}*`pXFbI{Y6G08PF@k4Hi0q?X{?i#-DQ$7v9SyOgqsHauLcHMQ;J^OAX6`*DVJ#VO=vZnP^kQ u6!We!>!!$iWKxYL;Zq1dBcl?DC*TkHpIV?pzHZq70000P)t-svl&AF z|NjaxVeH1x*^HsaQ*sP6V<1CsCrNZQRefF-f( zkFmYYaEGJo#m||lzV!C^a$kXWuRIR`00ACJL_t(Y$L*BCZo)7W1kC{Z?8YRH38DZ0 zrM*BQ7D{C+hgNhBR_3x&w5#X%0apt)1yI)s!eo?QAElwKc*5`mNmB*|>) z?CZEVfNu2Q#}0Hp>)Byf$H{?Vo|NPb!~3N-1X@3UViXL$QTm}02QeVJ4iTbI;SHrg zm@mruJ*Ic*B3ly&=E9<;??+8}kQRK5WeYad-#5 Y0Qfs0tx!$8>Hq)$07*qoM6N<$f^rwar2qf` literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/us.png b/apps/36-blocks/src/assets/images/flags/us.png new file mode 100644 index 0000000000000000000000000000000000000000..058fd15c16f2ced68d0165aa4b45dcabee8050ed GIT binary patch literal 430 zcmV;f0a5;mP)P)t-svl&AF z|NjaxVeH1x*^HsaQ*sP6V<1CsCrNZQRefF-f( zkFmYYaEGJo#m||lzV!C^a$kXWuRIR`00ACJL_t(Y$L*BCZo)7W1kC{Z?8YRH38DZ0 zrM*BQ7D{C+hgNhBR_3x&w5#X%0apt)1yI)s!eo?QAElwKc*5`mNmB*|>) z?CZEVfNu2Q#}0Hp>)Byf$H{?Vo|NPb!~3N-1X@3UViXL$QTm}02QeVJ4iTbI;SHrg zm@mruJ*Ic*B3ly&=E9<;??+8}kQRK5WeYad-#5 Y0Qfs0tx!$8>Hq)$07*qoM6N<$f^rwar2qf` literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/uy.png b/apps/36-blocks/src/assets/images/flags/uy.png new file mode 100644 index 0000000000000000000000000000000000000000..6226d59ab369017ec49466c087035b30b6de41c1 GIT binary patch literal 504 zcmVw~FuR z-QUWlptaxm&J^IlWA4EcgGd1E*{9jCH-Mbf(Aw`cdI*os2ZcquO)9tGt|CB7<}-pRaPUlYT^8}|cQ+jBu0$cfkSEk+-B`GD z^as7ZUf~s)IcTf{!eVnoUj6k-T}iaJYRh2Pt_jLQLJM_uw4;aU1X=qL_WJxP;schC z?aRa5bvbITwDx=9&~Mq=Vv`xjp{dn4;pACXU7IS5kDf_rTTtPh^QL)Rn3FLrSi#LB zlvqZE=6J7mH4g&fCkQ+w6?(EpO#%T#Xg uG?`O4L3o+WIX8ci=gFL-_ZNjH|A2SU(;GZ>O$Yq|0000|<@Yv!j5i z!zY2+agUliP6?w;O`V8nI22WQ%mvv4FO#oXLSs?%b literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/va.png b/apps/36-blocks/src/assets/images/flags/va.png new file mode 100644 index 0000000000000000000000000000000000000000..4132d67f1facf975a6bf1759172e5b5a47c3e028 GIT binary patch literal 1113 zcmV-f1g86mP)md+Sk^osHn=YUe3aqp?!Pa-rnfw z=;73=*S~MDv9oI-9`5bx=j7k6k~i$XE#}&?+p#Fk&d#%@c&CXiX)!a=uRXhx9HD7! zomN@z=E$L-qNbT{-q*vBcO%r!y0Vx;@ax*Rq+fz5CxL*1>fgK8%A~}oOPYc?l#r0b zogduE%DJwGeSUzwwUxD#l95tUb2vG8czBzbnt4h;0sgeU^>QN+zal#_jY^F`@c$X6lEQaStJs(K!U}me>i7` z;qLA)2lbcZE&&rT0TVC*|2+_)n89N$UJx2Gj5nb&p<@Jjs0o6G_}IVo zovBmcf`BX3e&5~%+Mz~KI+sol`dpMy3+}I&U+~=^|Kk6DD)B{@;7y=N@s@Z+Ovi!+u z0hvo<(9&3j)q`2KIzc2;hSiqfP^=v(9G4C_ZUior5QMh~8UoIMOl+NNWE3|C*eKFKOQfM}rfE_pW7xMUmd znWSwf@#$bnLmdnxvv-6@S6uIs)w#TTd9INaMVwYv2Sr!*($|`28Vy(9E6Vf0Bd#*V zKOR&j#4~9%?7WQXcs2=}+H;jB-yE1I3xbrt&RNz5=)XQy4s-hk%e=I6x!fAYwPQnL zRIse!P-1Qce*s9$54^(C8deVL5dL{g0ye!~W_J?Io$D?>a|_9wa5c3aKPo;=IOVdP zYG1-k`3kn9oVLH8=3Z1yC0}~iU0002fNkly?eu2iQx`1)0i}e!~m_y%H`C7F0)U9}57rWS*>p<00000NkvXXu0mjfSy^=h literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/vg.png b/apps/36-blocks/src/assets/images/flags/vg.png new file mode 100644 index 0000000000000000000000000000000000000000..3b5e3767ecdc615a2f8c87abf4326d7b531b7587 GIT binary patch literal 938 zcmV;b16BNqP)EY zS&sr?DDlI~b%m+{TqV{_V#p9K|Ns9CD{xh7n_Y946=EVEY(MMm^7ZxhUVI^ckFzXo zBR^J&@A33{im=l_Sp3E?IB+BaUnVBO;c z)~PP%z{&t%C|phuO@d<3*V3@5m>@iRzOjtb!JnOa8uZiI>%BmFg&{_DAU$p%ijE^n zVU*QMU_VqCx1fNNu$q3Oi|Dp1v$U%pQ5>CpjhR4SAv-`8#GgFgttFYGx>;?O%dTPY;^S9(Opus#psdFLAZU(T8f$+y zr}KOF0007ANkl*!D7zc2&y1GOzQ43fIiUh?go~^ghdPdDz+wcEPx}M`= zGGoNP=uH1Jj0+>bS>}0opnM*L!V#L<nZG%BZumE6lDbOy7771<}JB*OW z=l}B6yKC$Sx4UxG*daE_l<+g#yv@#JxqJj3aEGtnhh&IVJEj1-hLP4}JtjLqf+L5+ z2P7_vA_7nw8uhmsUXWmrCvPIhmv>K+V6jrvG&?-dlEsqXtTMR==YaKY_fLRUNf5Oz z$EOvhBRF>Ge5B(~z-E^O2tZtZ?HVs>D~{XnohpAWD==B9ym3Zr)rZ9kfNcf{LY)uW zuw7PxYw${q%Oax;dEQ`Gs|$dl9uuuP$A`7@LNB=nqj)&r+0ft-Kb)xyfKM(#N{b6Z z*{U0ew^yrF#vMoJTB%M&RT=|3*I+sot(9{n(ltp+PjTnSit<|lu<fY-OUf z%Q9E9g|V5J^3r%*$Uad^%5~^b?YY{QUgr=;)IGEcC@a7A9xSr83~OH`%T<{{H^rwm0}W)~qz%vo->DwC%n+^6~J{s58BoEfRaP6eMBOwO`@lm~YI_%7USWHiojqx|vIesk)|Y z0DHbGFNGKg0=Yg_@KMXti#WDpMATof;xSnIzw*IuvVy?V^dUQkgb%N zvz?wIM}T-f&&ad7pjN1klcQ~Un`KafsE3(YNUgfOV3@bquRPzoQk_v~c72-Vyh3Am zV8pPtsNje>000ILNklAc zc&yiY&x~{a^V>lkQNbOb`(gLJspOH6bpN`ly1Kezv;CC+sxVCA(f1CA{x~4PFztVJ zsTlA&x-$n#&@=D|&EX9crS>6x9v2d!Cy=psYM8S>ZQ4mX{adhfW_|-kRnL3_wFzr$YBGD3SwoW=8d*%Ix`UUPYVe7 zn|HfJy){E-ks?9^bI^0o$pbRrAd~=>4Ma5cWCv~=@cgoZ5Gu8G(Fd{~q8Tz|j3o#; zAkW;>o(>c#4j7PSRZ}C1Dgt5N%u-Y%JR~mOv>nLq5(g=wW~!P74Zu;w0R7PQWl5j} z)iALpsieP3vHmMRH*1!HsCaxmgMOBhtOk;XiEmj^kjj}()8&Bs5^dQcMG-%yI7xvl5;)`u62E0U#H$#%5Ug7C zpa($#2@pwK3P_L=i`lLr+MEiJCS+h$Pz;wOqQKDV{^!p}`O*E}-u==1=-TJ~)wKW; zB?T+3W@LDI%GW*Q`9KkJoRPwi^Z=-2U+aBAj_cEs7rkrt5(4Bk#3_RWMlrxYzG#nS zqNHiCE&-q~{?XnS_oVm8{{;cT#Tq6jfl$@)PicbpUuqDTkmW=YXZeS~QQ}dNV_^tD z?b6>_y#$f(7khLW1JmR{s5>wORMP}_IYZw=T+3P{GDI#z)`dyh^=kG~N(mySIs+*z zQhDjp<8NC!;Yj5D?Y};!bDUg)PB&u<<}R2iy{d|)=91L>>($jiS6^EvImo&CdQ>%B ztSPEhov26OxR7zW+q~I~^;;T-`{TaZOd&Zt*NpCBh(n0oZM^w3)pPc(=k#UIx3iwc zr#FpV7Rgw{yHTs>QeQ`)ExZ!5+kEkrxAtV=FgKsnZN~zl1R11*f4yRQ{`j@$P;{WWR^nIadVBfMK<)#Kw@){{1A&9g}Jf$xr&4K54#`><*EC?DOqEoYuHb3 zE+r!U@kD1}%jWP3c})io#wIESVo9`CWN=4Q-vmL>(?Fs9qdk2}F$Q4NJOjJ&AD&&ura43b}ou0k}DHE5X{!j{>=*^w=rC8!e zOR>JjTp@R~H;uINHsdh_&dkfC0?3;jD|wjhvWBK>U%xKsKVI9-ZEedGQfg724q#C- zG$|jF^O9yrA_&lYw5BMOy!eD_k!~)_0%%QUTEnUapqx(25U?C((+;ax8=IDw>8BK+ zGbuB-XWc9sDux2U0tJAzaY~kA<6|R7Deu!t+GsUdXob-tfLP#U(IrEHB;7?4CzJJ& zk;UkftK_L%(u!JsS%s2o*rg1+Bu!l=ym6;j3|D0RIO7|1JRkvjG3w0RPJX|C9j#836xG0RMsj|3Lu%zJlu{f4KvFJ)OEDodxEWV@* z;T?J%2wJL)HHKr?M#Vrb8YoKQN2n*u_VsDD7YuZS6VAbx>7JA zK*Vj%NJ6u_kwSdD za4d?ci0mRtl7S>9N;im`l!tV8&nNALGk})taLn?`01C*rmfTe)kOVJ!vT@|;$^Zhi zlE_2s$VUbcKoPkQAmLBcj!c9jKLfy4MK?0DWU-PQj5u{WPz^83_2f{67AT}G?&_9r zSrAz+?`?g48D=@{7sTYZFcTuPo;+P2=Z5=yf|)6WC{2gE7)EkWWDUz>i!G=st-)-@ z6e;rqky0%NB?^d&BBE#M~LS}Fpgv%$w+j#z56laI`I4$?qSk4_Mx_0 zj|CLP-i?(;ZN|b0xn#%-lvSEl6=Kb?C^kn`Nm(X#6AO;A>32&*U7`NBu#cCAx#2Y~ zngPjwTkm+*^J4-I6Mxzq7I8jkl=0iw&=HRhTCW7}8f?6Z`wRLb;CnfD5BfuD6*mR_ zG5UScIuP^+y;;kRpnntz;BKIQ{)#WpIuM+2Z$TV^{(&=?v*36n1`*C#a6Ghga0Cv2 uE52Ab3-;~!>#UiAnRDQgk+UE#r}YoY>Sw+ghu(Mq0000;}!+epBq? z=KcNmFROV=c=2jco6d^<-P;e}e)#Oeh3n6!tvD^cxl<6RtI^ZNF~s6@a>4;7mW>Q8 zI^E2LTr)RK(-cTg%4V4uHd|GA@dQpMQGt*X_ZXCF{j~%FPMD-yc0A%z%vkhNP2gmt zQ^3OCJdc>?G%lR!(dx5Zs>9^s+=$hkCCZx_CvsV;3oM_In!SawP;C~QaAs+g)I=`P n86UJoRD^o8WI`=g3Ggtm%EZMPGkk9ZI)=g1)z4*}Q$iB}|FKfz literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/ye.png b/apps/36-blocks/src/assets/images/flags/ye.png new file mode 100644 index 0000000000000000000000000000000000000000..eade987d0c114f10e68b85b1c76de6add7420015 GIT binary patch literal 127 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!VDx;*b2*m6n}tEi0e5)H6Zi<|NjmS4!3+_ z9GBkO3FK>gx;Tb-98XS=U|pP`!6dH4*eo`qTLyk)?%mena)P9VQzC_xt&7vX|@c^&f{{)ac-g!K`wW zG{~wYWRN$!rzZk;NL*>OFp+Eh^6}$ML&D$FZ%_;Df_r;d4aScZ7ATbVu^O_t+zNb9 z_Q%A~mKL_W-S))6%##)vDwRQ*cRwx%?TLcAxsN*l00C1;L_t(o!>!keR)a7Qh2aq= zC{Sx#LF-m)7x(vnJ`*Ae*-SEXAK*XV355c{u>JB>?e*@2G#IU%tK#h=TaX0_)0GP< z(g@O#U~Nr9!pcr+BHlz*)ke7+bA;^aO4NBy582NP`vr!P6r!X>V;~?Tg_$1SV3`ip= zk=~OmWA`Lq4TD}O_(>oIg6S3pW@~1-ixR~EUze1fLND8v?bdZtP2mQQ7 zGEW7MJQw#b=;5uicsf|OzIW`j(;I@EJQZwx-zhmf6=dbPf||G67Cga{#xsL^D$fY& hFM0}Z66D~?eFLR|G#A-ZaykG2002ovPDHLkV1i}N_oDy+ literal 0 HcmV?d00001 diff --git a/apps/36-blocks/src/assets/images/flags/zm.png b/apps/36-blocks/src/assets/images/flags/zm.png new file mode 100644 index 0000000000000000000000000000000000000000..b8d7f06dd1652cecb8385412fa8347de8bd82302 GIT binary patch literal 292 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfZ!3-oHew$MUq|5?*LR=-g7$ln+w!|_VPiLre zWa#weyd=l}z7{CWa8E(tavpEaj? zaro_((|k;dJggToS1+nP^#A{wgtSH3Y>T_^ZBWqhYY^L}`+0W5f$D!7c{V4o?A#kr zI9+yf#|%;4P)SptJv$g8EOxEl_R=_dtxtzb%#4{U&Ibmj{u5jJvcM{0$Kl!ytLCou zULo}9#Etk|rsvtZ%dV7nZIxP+wcuHtb4sjtR5u%Ubj+4rYimsyeir|6T-R^A{r5y~ j%Sj1MoN6*28A%bmRf0L>v3HZ1@ESO78>0NX1o>5+>#aRAL*0QAbrwQ2y# zt7iA<*|}u^$VvduK>($F0K_^3;H0;b0003{NklNzj4pAe9J)YA@IH9WoWKJ7=P{#aZe!DWXEOiy$Fsn;o*$d_@s2RBaYc(rH`E zvy;*)XSpquj^p^pPA6^av~)Fggo>5Y(IGtQZ32+*ib!c4$@$cWE(I8-zf$_ruP2^I zQs(vEms0LUGTuC-qVS#lEw$EPVms(kj*Us0Z>zE_tIej@T@gDa=u|`2EC8(+vguZ& z=pOg-QFSrb*H~TH1>08__XM=M&_@dXjJn{5-ouU}=wZnPk8>V&;6#taE_i77z`qs$ X;Y?gBiUc#Z00000NkvXXu0mjf`n3p# literal 0 HcmV?d00001 diff --git a/apps/shared/assets/utils/countries-info.ts b/apps/shared/assets/utils/countries-info.ts new file mode 100644 index 00000000..e52a5f97 --- /dev/null +++ b/apps/shared/assets/utils/countries-info.ts @@ -0,0 +1,2261 @@ +/** Interface for country data - simplified for use with Google libphonenumber */ +export interface Country { + /** Country name in English */ + name: string; + /** ISO 3166-1 alpha-2 country code */ + code: string; + /** International dialing code */ + dialCode: string; + /** Unicode flag emoji */ + flag: string; + /** Path to flag image */ + flagImage?: string; + /** Country name in native language */ + nativeName: string; + /** Realistic mobile number placeholder example (without country code) */ + placeholder?: string; +} +/** Comprehensive list of all countries with their telephone data */ +export const COUNTRIES_DATA: Country[] = [ + { + name: 'United States', + code: 'US', + dialCode: '+1', + flag: '🇺🇸', + flagImage: 'assets/images/flags/us.png', + nativeName: 'United States', + placeholder: '2015550123', + }, + { + name: 'United Kingdom', + code: 'GB', + dialCode: '+44', + flag: '🇬🇧', + flagImage: 'assets/images/flags/gb.png', + nativeName: 'United Kingdom', + placeholder: '07400123456', + }, + // A + { + name: 'Åland Islands', + code: 'AX', + dialCode: '+358', + flag: '🇦🇽', + flagImage: 'assets/images/flags/ax.png', + nativeName: 'Åland', + placeholder: '0401234567', + }, + { + name: 'Afghanistan', + code: 'AF', + dialCode: '+93', + flag: '🇦🇫', + flagImage: 'assets/images/flags/af.png', + nativeName: 'افغانستان', + placeholder: '0701234567', + }, + { + name: 'Albania', + code: 'AL', + dialCode: '+355', + flag: '🇦🇱', + flagImage: 'assets/images/flags/al.png', + nativeName: 'Shqipëria', + placeholder: '0671234567', + }, + { + name: 'Algeria', + code: 'DZ', + dialCode: '+213', + flag: '🇩🇿', + flagImage: 'assets/images/flags/dz.png', + nativeName: 'الجزائر', + placeholder: '0551234567', + }, + { + name: 'American Samoa', + code: 'AS', + dialCode: '+1684', + flag: '🇦🇸', + flagImage: 'assets/images/flags/as.png', + nativeName: 'Amerika Sāmoa', + placeholder: '6841234567', + }, + { + name: 'Andorra', + code: 'AD', + dialCode: '+376', + flag: '🇦🇩', + flagImage: 'assets/images/flags/ad.png', + nativeName: 'Andorra', + placeholder: '312345', + }, + { + name: 'Angola', + code: 'AO', + dialCode: '+244', + flag: '🇦🇴', + flagImage: 'assets/images/flags/ao.png', + nativeName: 'Angola', + placeholder: '923123456', + }, + { + name: 'Anguilla', + code: 'AI', + dialCode: '+1264', + flag: '🇦🇮', + flagImage: 'assets/images/flags/ai.png', + nativeName: 'Anguilla', + placeholder: '2642351234', + }, + { + name: 'Antigua and Barbuda', + code: 'AG', + dialCode: '+1268', + flag: '🇦🇬', + flagImage: 'assets/images/flags/ag.png', + nativeName: 'Antigua and Barbuda', + placeholder: '2687201234', + }, + { + name: 'Argentina', + code: 'AR', + dialCode: '+54', + flag: '🇦🇷', + flagImage: 'assets/images/flags/ar.png', + nativeName: 'Argentina', + placeholder: '1123456789', + }, + { + name: 'Armenia', + code: 'AM', + dialCode: '+374', + flag: '🇦🇲', + flagImage: 'assets/images/flags/am.png', + nativeName: 'Հայաստան', + placeholder: '077123456', + }, + { + name: 'Aruba', + code: 'AW', + dialCode: '+297', + flag: '🇦🇼', + flagImage: 'assets/images/flags/aw.png', + nativeName: 'Aruba', + placeholder: '5601234', + }, + { + name: 'Australia', + code: 'AU', + dialCode: '+61', + flag: '🇦🇺', + flagImage: 'assets/images/flags/au.png', + nativeName: 'Australia', + placeholder: '0412345678', + }, + { + name: 'Austria', + code: 'AT', + dialCode: '+43', + flag: '🇦🇹', + flagImage: 'assets/images/flags/at.png', + nativeName: 'Österreich', + placeholder: '06641234567', + }, + { + name: 'Azerbaijan', + code: 'AZ', + dialCode: '+994', + flag: '🇦🇿', + flagImage: 'assets/images/flags/az.png', + nativeName: 'Azərbaycan', + placeholder: '0401234567', + }, + // B + { + name: 'Bahamas', + code: 'BS', + dialCode: '+1242', + flag: '🇧🇸', + flagImage: 'assets/images/flags/bs.png', + nativeName: 'The Bahamas', + placeholder: '2423591234', + }, + { + name: 'Bahrain', + code: 'BH', + dialCode: '+973', + flag: '🇧🇭', + flagImage: 'assets/images/flags/bh.png', + nativeName: 'البحرين', + placeholder: '36001234', + }, + { + name: 'Bangladesh', + code: 'BD', + dialCode: '+880', + flag: '🇧🇩', + flagImage: 'assets/images/flags/bd.png', + nativeName: 'বাংলাদেশ', + placeholder: '01712345678', + }, + { + name: 'Barbados', + code: 'BB', + dialCode: '+1246', + flag: '🇧🇧', + flagImage: 'assets/images/flags/bb.png', + nativeName: 'Barbados', + placeholder: '2462501234', + }, + { + name: 'Belarus', + code: 'BY', + dialCode: '+375', + flag: '🇧🇾', + flagImage: 'assets/images/flags/by.png', + nativeName: 'Беларусь', + placeholder: '0291234567', + }, + { + name: 'Belgium', + code: 'BE', + dialCode: '+32', + flag: '🇧🇪', + flagImage: 'assets/images/flags/be.png', + nativeName: 'België / Belgique', + placeholder: '0470123456', + }, + { + name: 'Belize', + code: 'BZ', + dialCode: '+501', + flag: '🇧🇿', + flagImage: 'assets/images/flags/bz.png', + nativeName: 'Belize', + placeholder: '6221234', + }, + { + name: 'Benin', + code: 'BJ', + dialCode: '+229', + flag: '🇧🇯', + flagImage: 'assets/images/flags/bj.png', + nativeName: 'Bénin', + placeholder: '97123456', + }, + { + name: 'Bermuda', + code: 'BM', + dialCode: '+1441', + flag: '🇧🇲', + flagImage: 'assets/images/flags/bm.png', + nativeName: 'Bermuda', + placeholder: '4412921234', + }, + { + name: 'Bhutan', + code: 'BT', + dialCode: '+975', + flag: '🇧🇹', + flagImage: 'assets/images/flags/bt.png', + nativeName: 'འབྲུག', + placeholder: '17123456', + }, + { + name: 'Bolivia', + code: 'BO', + dialCode: '+591', + flag: '🇧🇴', + flagImage: 'assets/images/flags/bo.png', + nativeName: 'Bolivia', + placeholder: '71234567', + }, + { + name: 'Bosnia and Herzegovina', + code: 'BA', + dialCode: '+387', + flag: '🇧🇦', + flagImage: 'assets/images/flags/ba.png', + nativeName: 'Bosna i Hercegovina', + placeholder: '061123456', + }, + { + name: 'Botswana', + code: 'BW', + dialCode: '+267', + flag: '🇧🇼', + flagImage: 'assets/images/flags/bw.png', + nativeName: 'Botswana', + placeholder: '71123456', + }, + { + name: 'Brazil', + code: 'BR', + dialCode: '+55', + flag: '🇧🇷', + flagImage: 'assets/images/flags/br.png', + nativeName: 'Brasil', + placeholder: '11987654321', + }, + { + name: 'British Indian Ocean Territory', + code: 'IO', + dialCode: '+246', + flag: '🇮🇴', + flagImage: 'assets/images/flags/io.png', + nativeName: 'British Indian Ocean Territory', + placeholder: '3801401', + }, + { + name: 'British Virgin Islands', + code: 'VG', + dialCode: '+1284', + flag: '🇻🇬', + flagImage: 'assets/images/flags/vg.png', + nativeName: 'British Virgin Islands', + placeholder: '2843001234', + }, + { + name: 'Brunei', + code: 'BN', + dialCode: '+673', + flag: '🇧🇳', + flagImage: 'assets/images/flags/bn.png', + nativeName: 'Brunei Darussalam', + placeholder: '7121234', + }, + { + name: 'Bulgaria', + code: 'BG', + dialCode: '+359', + flag: '🇧🇬', + flagImage: 'assets/images/flags/bg.png', + nativeName: 'България', + placeholder: '0871234567', + }, + { + name: 'Burkina Faso', + code: 'BF', + dialCode: '+226', + flag: '🇧🇫', + flagImage: 'assets/images/flags/bf.png', + nativeName: 'Burkina Faso', + placeholder: '70123456', + }, + { + name: 'Burundi', + code: 'BI', + dialCode: '+257', + flag: '🇧🇮', + flagImage: 'assets/images/flags/bi.png', + nativeName: 'Burundi', + placeholder: '79561234', + }, + // C + { + name: 'Cambodia', + code: 'KH', + dialCode: '+855', + flag: '🇰🇭', + flagImage: 'assets/images/flags/kh.png', + nativeName: 'កម្ពុជា', + placeholder: '012345678', + }, + { + name: 'Cameroon', + code: 'CM', + dialCode: '+237', + flag: '🇨🇲', + flagImage: 'assets/images/flags/cm.png', + nativeName: 'Cameroun', + placeholder: '671234567', + }, + { + name: 'Canada', + code: 'CA', + dialCode: '+1', + flag: '🇨🇦', + flagImage: 'assets/images/flags/ca.png', + nativeName: 'Canada', + placeholder: '4165551234', + }, + { + name: 'Cape Verde', + code: 'CV', + dialCode: '+238', + flag: '🇨🇻', + flagImage: 'assets/images/flags/cv.png', + nativeName: 'Cabo Verde', + placeholder: '9911234', + }, + { + name: 'Caribbean Netherlands', + code: 'BQ', + dialCode: '+599', + flag: '🇧🇶', + flagImage: 'assets/images/flags/bq.png', + nativeName: 'Caribbean Netherlands', + }, + { + name: 'Cayman Islands', + code: 'KY', + dialCode: '+1345', + flag: '🇰🇾', + flagImage: 'assets/images/flags/ky.png', + nativeName: 'Cayman Islands', + placeholder: '3453231234', + }, + { + name: 'Central African Republic', + code: 'CF', + dialCode: '+236', + flag: '🇨🇫', + flagImage: 'assets/images/flags/cf.png', + nativeName: 'République Centrafricaine', + placeholder: '72001234', + }, + { + name: 'Chad', + code: 'TD', + dialCode: '+235', + flag: '🇹🇩', + flagImage: 'assets/images/flags/td.png', + nativeName: 'تشاد', + placeholder: '63012345', + }, + { + name: 'Chile', + code: 'CL', + dialCode: '+56', + flag: '🇨🇱', + flagImage: 'assets/images/flags/cl.png', + nativeName: 'Chile', + placeholder: '912345678', + }, + { + name: 'China', + code: 'CN', + dialCode: '+86', + flag: '🇨🇳', + flagImage: 'assets/images/flags/cn.png', + nativeName: '中国', + placeholder: '13800138000', + }, + { + name: 'Christmas Island', + code: 'CX', + dialCode: '+61', + flag: '🇨🇽', + flagImage: 'assets/images/flags/cx.png', + nativeName: 'Christmas Island', + placeholder: '0412345678', + }, + { + name: 'Cocos (Keeling) Islands', + code: 'CC', + dialCode: '+61', + flag: '🇨🇨', + flagImage: 'assets/images/flags/cc.png', + nativeName: 'Cocos (Keeling) Islands', + placeholder: '0412345678', + }, + { + name: 'Colombia', + code: 'CO', + dialCode: '+57', + flag: '🇨🇴', + flagImage: 'assets/images/flags/co.png', + nativeName: 'Colombia', + placeholder: '3001234567', + }, + { + name: 'Comoros', + code: 'KM', + dialCode: '+269', + flag: '🇰🇲', + flagImage: 'assets/images/flags/km.png', + nativeName: 'Komori', + placeholder: '3211234', + }, + { + name: 'Congo', + code: 'CG', + dialCode: '+242', + flag: '🇨🇬', + flagImage: 'assets/images/flags/cg.png', + nativeName: 'Congo', + placeholder: '061234567', + }, + { + name: 'Democratic Republic of the Congo', + code: 'CD', + dialCode: '+243', + flag: '🇨🇩', + flagImage: 'assets/images/flags/cd.png', + nativeName: 'République Démocratique du Congo', + placeholder: '0991234567', + }, + { + name: 'Cook Islands', + code: 'CK', + dialCode: '+682', + flag: '🇨🇰', + flagImage: 'assets/images/flags/ck.png', + nativeName: 'Cook Islands', + placeholder: '71234', + }, + { + name: 'Costa Rica', + code: 'CR', + dialCode: '+506', + flag: '🇨🇷', + flagImage: 'assets/images/flags/cr.png', + nativeName: 'Costa Rica', + placeholder: '83123456', + }, + { + name: 'Croatia', + code: 'HR', + dialCode: '+385', + flag: '🇭🇷', + flagImage: 'assets/images/flags/hr.png', + nativeName: 'Hrvatska', + placeholder: '0912345678', + }, + { + name: 'Cuba', + code: 'CU', + dialCode: '+53', + flag: '🇨🇺', + flagImage: 'assets/images/flags/cu.png', + nativeName: 'Cuba', + placeholder: '051234567', + }, + { + name: 'Curaçao', + code: 'CW', + dialCode: '+599', + flag: '🇨🇼', + flagImage: 'assets/images/flags/cw.png', + nativeName: 'Curaçao', + placeholder: '95512345', + }, + { + name: 'Cyprus', + code: 'CY', + dialCode: '+357', + flag: '🇨🇾', + flagImage: 'assets/images/flags/cy.png', + nativeName: 'Κύπρος', + placeholder: '96123456', + }, + { + name: 'Czech Republic', + code: 'CZ', + dialCode: '+420', + flag: '🇨🇿', + flagImage: 'assets/images/flags/cz.png', + nativeName: 'Česká republika', + placeholder: '601234567', + }, + // D + { + name: 'Denmark', + code: 'DK', + dialCode: '+45', + flag: '🇩🇰', + flagImage: 'assets/images/flags/dk.png', + nativeName: 'Danmark', + placeholder: '20123456', + }, + { + name: 'Djibouti', + code: 'DJ', + dialCode: '+253', + flag: '🇩🇯', + flagImage: 'assets/images/flags/dj.png', + nativeName: 'Djibouti', + placeholder: '77831001', + }, + { + name: 'Dominica', + code: 'DM', + dialCode: '+1767', + flag: '🇩🇲', + flagImage: 'assets/images/flags/dm.png', + nativeName: 'Dominica', + placeholder: '7672251234', + }, + { + name: 'Dominican Republic', + code: 'DO', + dialCode: '+1809', + flag: '🇩🇴', + flagImage: 'assets/images/flags/do.png', + nativeName: 'República Dominicana', + placeholder: '8091234567', + }, + // E + { + name: 'Ecuador', + code: 'EC', + dialCode: '+593', + flag: '🇪🇨', + flagImage: 'assets/images/flags/ec.png', + nativeName: 'Ecuador', + placeholder: '0991234567', + }, + { + name: 'Egypt', + code: 'EG', + dialCode: '+20', + flag: '🇪🇬', + flagImage: 'assets/images/flags/eg.png', + nativeName: 'مصر', + placeholder: '01001234567', + }, + { + name: 'El Salvador', + code: 'SV', + dialCode: '+503', + flag: '🇸🇻', + flagImage: 'assets/images/flags/sv.png', + nativeName: 'El Salvador', + placeholder: '70123456', + }, + { + name: 'Equatorial Guinea', + code: 'GQ', + dialCode: '+240', + flag: '🇬🇶', + flagImage: 'assets/images/flags/gq.png', + nativeName: 'Guinea Ecuatorial', + placeholder: '222123456', + }, + { + name: 'Eritrea', + code: 'ER', + dialCode: '+291', + flag: '🇪🇷', + flagImage: 'assets/images/flags/er.png', + nativeName: 'ኤርትራ', + placeholder: '07123456', + }, + { + name: 'Estonia', + code: 'EE', + dialCode: '+372', + flag: '🇪🇪', + flagImage: 'assets/images/flags/ee.png', + nativeName: 'Eesti', + placeholder: '51234567', + }, + { + name: 'Eswatini', + code: 'SZ', + dialCode: '+268', + flag: '🇸🇿', + flagImage: 'assets/images/flags/sz.png', + nativeName: 'Eswatini', + placeholder: '76123456', + }, + { + name: 'Ethiopia', + code: 'ET', + dialCode: '+251', + flag: '🇪🇹', + flagImage: 'assets/images/flags/et.png', + nativeName: 'ኢትዮጵያ', + placeholder: '0911234567', + }, + // F + { + name: 'Falkland Islands', + code: 'FK', + dialCode: '+500', + flag: '🇫🇰', + flagImage: 'assets/images/flags/fk.png', + nativeName: 'Falkland Islands', + placeholder: '51234', + }, + { + name: 'Faroe Islands', + code: 'FO', + dialCode: '+298', + flag: '🇫🇴', + flagImage: 'assets/images/flags/fo.png', + nativeName: 'Føroyar', + placeholder: '211234', + }, + { + name: 'Fiji', + code: 'FJ', + dialCode: '+679', + flag: '🇫🇯', + flagImage: 'assets/images/flags/fj.png', + nativeName: 'Fiji', + placeholder: '7012345', + }, + { + name: 'Finland', + code: 'FI', + dialCode: '+358', + flag: '🇫🇮', + flagImage: 'assets/images/flags/fi.png', + nativeName: 'Suomi', + placeholder: '0401234567', + }, + { + name: 'France', + code: 'FR', + dialCode: '+33', + flag: '🇫🇷', + flagImage: 'assets/images/flags/fr.png', + nativeName: 'France', + placeholder: '0612345678', + }, + { + name: 'French Guiana', + code: 'GF', + dialCode: '+594', + flag: '🇬🇫', + flagImage: 'assets/images/flags/gf.png', + nativeName: 'Guyane française', + placeholder: '0694201234', + }, + { + name: 'French Polynesia', + code: 'PF', + dialCode: '+689', + flag: '🇵🇫', + flagImage: 'assets/images/flags/pf.png', + nativeName: 'Polynésie française', + placeholder: '87123456', + }, + // G + { + name: 'Gabon', + code: 'GA', + dialCode: '+241', + flag: '🇬🇦', + flagImage: 'assets/images/flags/ga.png', + nativeName: 'Gabon', + placeholder: '06031234', + }, + { + name: 'Gambia', + code: 'GM', + dialCode: '+220', + flag: '🇬🇲', + flagImage: 'assets/images/flags/gm.png', + nativeName: 'Gambia', + placeholder: '3012345', + }, + { + name: 'Georgia', + code: 'GE', + dialCode: '+995', + flag: '🇬🇪', + flagImage: 'assets/images/flags/ge.png', + nativeName: 'საქართველო', + placeholder: '555123456', + }, + { + name: 'Germany', + code: 'DE', + dialCode: '+49', + flag: '🇩🇪', + flagImage: 'assets/images/flags/de.png', + nativeName: 'Deutschland', + placeholder: '01512345678', + }, + { + name: 'Ghana', + code: 'GH', + dialCode: '+233', + flag: '🇬🇭', + flagImage: 'assets/images/flags/gh.png', + nativeName: 'Ghana', + placeholder: '0241234567', + }, + { + name: 'Gibraltar', + code: 'GI', + dialCode: '+350', + flag: '🇬🇮', + flagImage: 'assets/images/flags/gi.png', + nativeName: 'Gibraltar', + placeholder: '57123456', + }, + { + name: 'Greece', + code: 'GR', + dialCode: '+30', + flag: '🇬🇷', + flagImage: 'assets/images/flags/gr.png', + nativeName: 'Ελλάδα', + placeholder: '6912345678', + }, + { + name: 'Greenland', + code: 'GL', + dialCode: '+299', + flag: '🇬🇱', + flagImage: 'assets/images/flags/gl.png', + nativeName: 'Kalaallit Nunaat', + placeholder: '321234', + }, + { + name: 'Grenada', + code: 'GD', + dialCode: '+1473', + flag: '🇬🇩', + flagImage: 'assets/images/flags/gd.png', + nativeName: 'Grenada', + placeholder: '4734031234', + }, + { + name: 'Guadeloupe', + code: 'GP', + dialCode: '+590', + flag: '🇬🇵', + flagImage: 'assets/images/flags/gp.png', + nativeName: 'Guadeloupe', + placeholder: '0690001234', + }, + { + name: 'Guam', + code: 'GU', + dialCode: '+1671', + flag: '🇬🇺', + flagImage: 'assets/images/flags/gu.png', + nativeName: 'Guåhan', + placeholder: '6713001234', + }, + { + name: 'Guatemala', + code: 'GT', + dialCode: '+502', + flag: '🇬🇹', + flagImage: 'assets/images/flags/gt.png', + nativeName: 'Guatemala', + placeholder: '51234567', + }, + { + name: 'Guernsey', + code: 'GG', + dialCode: '+44', + flag: '🇬🇬', + flagImage: 'assets/images/flags/gg.png', + nativeName: 'Guernsey', + placeholder: '07781123456', + }, + { + name: 'Guinea', + code: 'GN', + dialCode: '+224', + flag: '🇬🇳', + flagImage: 'assets/images/flags/gn.png', + nativeName: 'Guinée', + placeholder: '601123456', + }, + { + name: 'Guinea-Bissau', + code: 'GW', + dialCode: '+245', + flag: '🇬🇼', + flagImage: 'assets/images/flags/gw.png', + nativeName: 'Guiné-Bissau', + placeholder: '955012345', + }, + { + name: 'Guyana', + code: 'GY', + dialCode: '+592', + flag: '🇬🇾', + flagImage: 'assets/images/flags/gy.png', + nativeName: 'Guyana', + placeholder: '6091234567', + }, + // H + { + name: 'Haiti', + code: 'HT', + dialCode: '+509', + flag: '🇭🇹', + flagImage: 'assets/images/flags/ht.png', + nativeName: 'Haïti', + placeholder: '34101234', + }, + { + name: 'Honduras', + code: 'HN', + dialCode: '+504', + flag: '🇭🇳', + flagImage: 'assets/images/flags/hn.png', + nativeName: 'Honduras', + placeholder: '91234567', + }, + { + name: 'Hong Kong', + code: 'HK', + dialCode: '+852', + flag: '🇭🇰', + flagImage: 'assets/images/flags/hk.png', + nativeName: '香港', + placeholder: '51234567', + }, + { + name: 'Hungary', + code: 'HU', + dialCode: '+36', + flag: '🇭🇺', + flagImage: 'assets/images/flags/hu.png', + nativeName: 'Magyarország', + placeholder: '301234567', + }, + // I + { + name: 'Iceland', + code: 'IS', + dialCode: '+354', + flag: '🇮🇸', + flagImage: 'assets/images/flags/is.png', + nativeName: 'Ísland', + placeholder: '6111234', + }, + { + name: 'India', + code: 'IN', + dialCode: '+91', + flag: '🇮🇳', + flagImage: 'assets/images/flags/in.png', + nativeName: 'भारत', + placeholder: '9876543210', + }, + { + name: 'Indonesia', + code: 'ID', + dialCode: '+62', + flag: '🇮🇩', + flagImage: 'assets/images/flags/id.png', + nativeName: 'Indonesia', + placeholder: '081234567890', + }, + { + name: 'Iran', + code: 'IR', + dialCode: '+98', + flag: '🇮🇷', + flagImage: 'assets/images/flags/ir.png', + nativeName: 'ایران', + placeholder: '09121234567', + }, + { + name: 'Iraq', + code: 'IQ', + dialCode: '+964', + flag: '🇮🇶', + flagImage: 'assets/images/flags/iq.png', + nativeName: 'العراق', + placeholder: '07901234567', + }, + { + name: 'Ireland', + code: 'IE', + dialCode: '+353', + flag: '🇮🇪', + flagImage: 'assets/images/flags/ie.png', + nativeName: 'Éire', + placeholder: '0871234567', + }, + { + name: 'Isle of Man', + code: 'IM', + dialCode: '+44', + flag: '🇮🇲', + flagImage: 'assets/images/flags/im.png', + nativeName: 'Isle of Man', + placeholder: '07924123456', + }, + { + name: 'Israel', + code: 'IL', + dialCode: '+972', + flag: '🇮🇱', + flagImage: 'assets/images/flags/il.png', + nativeName: 'ישראל', + placeholder: '0501234567', + }, + { + name: 'Italy', + code: 'IT', + dialCode: '+39', + flag: '🇮🇹', + flagImage: 'assets/images/flags/it.png', + nativeName: 'Italia', + placeholder: '3123456789', + }, + { + name: 'Ivory Coast', + code: 'CI', + dialCode: '+225', + flag: '🇨🇮', + flagImage: 'assets/images/flags/ci.png', + nativeName: "Côte d'Ivoire", + }, + // J + { + name: 'Jamaica', + code: 'JM', + dialCode: '+1876', + flag: '🇯🇲', + flagImage: 'assets/images/flags/jm.png', + nativeName: 'Jamaica', + placeholder: '8762101234', + }, + { + name: 'Japan', + code: 'JP', + dialCode: '+81', + flag: '🇯🇵', + flagImage: 'assets/images/flags/jp.png', + nativeName: '日本', + placeholder: '09012345678', + }, + { + name: 'Jersey', + code: 'JE', + dialCode: '+44', + flag: '🇯🇪', + flagImage: 'assets/images/flags/je.png', + nativeName: 'Jersey', + placeholder: '07797712345', + }, + { + name: 'Jordan', + code: 'JO', + dialCode: '+962', + flag: '🇯🇴', + flagImage: 'assets/images/flags/jo.png', + nativeName: 'الأردن', + placeholder: '0791234567', + }, + // K + { + name: 'Kazakhstan', + code: 'KZ', + dialCode: '+7', + flag: '🇰🇿', + flagImage: 'assets/images/flags/kz.png', + nativeName: 'Қазақстан', + placeholder: '7071234567', + }, + { + name: 'Kenya', + code: 'KE', + dialCode: '+254', + flag: '🇰🇪', + flagImage: 'assets/images/flags/ke.png', + nativeName: 'Kenya', + placeholder: '0712345678', + }, + { + name: 'Kiribati', + code: 'KI', + dialCode: '+686', + flag: '🇰🇮', + flagImage: 'assets/images/flags/ki.png', + nativeName: 'Kiribati', + placeholder: '72001234', + }, + { + name: 'Kosovo', + code: 'XK', + dialCode: '+383', + flag: '🇽🇰', + flagImage: '', // No flag image available for Kosovo (XK) + nativeName: 'Kosovë', + placeholder: '044123456', + }, + { + name: 'Kuwait', + code: 'KW', + dialCode: '+965', + flag: '🇰🇼', + flagImage: 'assets/images/flags/kw.png', + nativeName: 'الكويت', + placeholder: '51234567', + }, + { + name: 'Kyrgyzstan', + code: 'KG', + dialCode: '+996', + flag: '🇰🇬', + flagImage: 'assets/images/flags/kg.png', + nativeName: 'Кыргызстан', + placeholder: '0700123456', + }, + // L + { + name: 'Laos', + code: 'LA', + dialCode: '+856', + flag: '🇱🇦', + flagImage: 'assets/images/flags/la.png', + nativeName: 'ລາວ', + placeholder: '020234567', + }, + { + name: 'Latvia', + code: 'LV', + dialCode: '+371', + flag: '🇱🇻', + flagImage: 'assets/images/flags/lv.png', + nativeName: 'Latvija', + placeholder: '21234567', + }, + { + name: 'Lebanon', + code: 'LB', + dialCode: '+961', + flag: '🇱🇧', + flagImage: 'assets/images/flags/lb.png', + nativeName: 'لبنان', + placeholder: '71123456', + }, + { + name: 'Lesotho', + code: 'LS', + dialCode: '+266', + flag: '🇱🇸', + flagImage: 'assets/images/flags/ls.png', + nativeName: 'Lesotho', + placeholder: '50123456', + }, + { + name: 'Liberia', + code: 'LR', + dialCode: '+231', + flag: '🇱🇷', + flagImage: 'assets/images/flags/lr.png', + nativeName: 'Liberia', + placeholder: '0770123456', + }, + { + name: 'Libya', + code: 'LY', + dialCode: '+218', + flag: '🇱🇾', + flagImage: 'assets/images/flags/ly.png', + nativeName: 'ليبيا', + placeholder: '0912345678', + }, + { + name: 'Liechtenstein', + code: 'LI', + dialCode: '+423', + flag: '🇱🇮', + flagImage: 'assets/images/flags/li.png', + nativeName: 'Liechtenstein', + placeholder: '660234567', + }, + { + name: 'Lithuania', + code: 'LT', + dialCode: '+370', + flag: '🇱🇹', + flagImage: 'assets/images/flags/lt.png', + nativeName: 'Lietuva', + placeholder: '61234567', + }, + { + name: 'Luxembourg', + code: 'LU', + dialCode: '+352', + flag: '🇱🇺', + flagImage: 'assets/images/flags/lu.png', + nativeName: 'Lëtzebuerg', + placeholder: '621123456', + }, + // M + { + name: 'Macau', + code: 'MO', + dialCode: '+853', + flag: '🇲🇴', + flagImage: 'assets/images/flags/mo.png', + nativeName: '澳門', + placeholder: '66123456', + }, + { + name: 'Madagascar', + code: 'MG', + dialCode: '+261', + flag: '🇲🇬', + flagImage: 'assets/images/flags/mg.png', + nativeName: 'Madagasikara', + placeholder: '321234567', + }, + { + name: 'Malawi', + code: 'MW', + dialCode: '+265', + flag: '🇲🇼', + flagImage: 'assets/images/flags/mw.png', + nativeName: 'Malawi', + placeholder: '0991234567', + }, + { + name: 'Malaysia', + code: 'MY', + dialCode: '+60', + flag: '🇲🇾', + flagImage: 'assets/images/flags/my.png', + nativeName: 'Malaysia', + placeholder: '0123456789', + }, + { + name: 'Maldives', + code: 'MV', + dialCode: '+960', + flag: '🇲🇻', + flagImage: 'assets/images/flags/mv.png', + nativeName: 'ދިވެހިބަސް', + placeholder: '7771234', + }, + { + name: 'Mali', + code: 'ML', + dialCode: '+223', + flag: '🇲🇱', + flagImage: 'assets/images/flags/ml.png', + nativeName: 'Mali', + placeholder: '65012345', + }, + { + name: 'Malta', + code: 'MT', + dialCode: '+356', + flag: '🇲🇹', + flagImage: 'assets/images/flags/mt.png', + nativeName: 'Malta', + placeholder: '99123456', + }, + { + name: 'Marshall Islands', + code: 'MH', + dialCode: '+692', + flag: '🇲🇭', + flagImage: 'assets/images/flags/mh.png', + nativeName: 'Marshall Islands', + placeholder: '2351234', + }, + { + name: 'Martinique', + code: 'MQ', + dialCode: '+596', + flag: '🇲🇶', + flagImage: 'assets/images/flags/mq.png', + nativeName: 'Martinique', + placeholder: '0696201234', + }, + { + name: 'Mauritania', + code: 'MR', + dialCode: '+222', + flag: '🇲🇷', + flagImage: 'assets/images/flags/mr.png', + nativeName: 'موريتانيا', + placeholder: '22123456', + }, + { + name: 'Mauritius', + code: 'MU', + dialCode: '+230', + flag: '🇲🇺', + flagImage: 'assets/images/flags/mu.png', + nativeName: 'Maurice', + placeholder: '52512345', + }, + { + name: 'Mayotte', + code: 'YT', + dialCode: '+262', + flag: '🇫🇷', + flagImage: 'assets/images/flags/fr.png', + nativeName: 'Mayotte', + placeholder: '0639012345', + }, + { + name: 'Mexico', + code: 'MX', + dialCode: '+52', + flag: '🇲🇽', + flagImage: 'assets/images/flags/mx.png', + nativeName: 'México', + placeholder: '5512345678', + }, + { + name: 'Micronesia', + code: 'FM', + dialCode: '+691', + flag: '🇫🇲', + flagImage: 'assets/images/flags/fm.png', + nativeName: 'Micronesia', + placeholder: '3501234', + }, + { + name: 'Moldova', + code: 'MD', + dialCode: '+373', + flag: '🇲🇩', + flagImage: 'assets/images/flags/md.png', + nativeName: 'Republica Moldova', + placeholder: '0621234567', + }, + { + name: 'Monaco', + code: 'MC', + dialCode: '+377', + flag: '🇲🇨', + flagImage: 'assets/images/flags/mc.png', + nativeName: 'Monaco', + placeholder: '0612345678', + }, + { + name: 'Mongolia', + code: 'MN', + dialCode: '+976', + flag: '🇲🇳', + flagImage: 'assets/images/flags/mn.png', + nativeName: 'Монгол', + placeholder: '88123456', + }, + { + name: 'Montenegro', + code: 'ME', + dialCode: '+382', + flag: '🇲🇪', + flagImage: 'assets/images/flags/me.png', + nativeName: 'Crna Gora', + placeholder: '067123456', + }, + { + name: 'Montserrat', + code: 'MS', + dialCode: '+1664', + flag: '🇲🇸', + flagImage: 'assets/images/flags/ms.png', + nativeName: 'Montserrat', + placeholder: '6644913456', + }, + { + name: 'Morocco', + code: 'MA', + dialCode: '+212', + flag: '🇲🇦', + flagImage: 'assets/images/flags/ma.png', + nativeName: 'المغرب', + placeholder: '0612345678', + }, + { + name: 'Mozambique', + code: 'MZ', + dialCode: '+258', + flag: '🇲🇿', + flagImage: 'assets/images/flags/mz.png', + nativeName: 'Moçambique', + placeholder: '821234567', + }, + { + name: 'Myanmar', + code: 'MM', + dialCode: '+95', + flag: '🇲🇲', + flagImage: 'assets/images/flags/mm.png', + nativeName: 'မြန်မာ', + placeholder: '09212345678', + }, + // N + { + name: 'Namibia', + code: 'NA', + dialCode: '+264', + flag: '🇳🇦', + flagImage: 'assets/images/flags/na.png', + nativeName: 'Namibië', + placeholder: '0811234567', + }, + { + name: 'Nauru', + code: 'NR', + dialCode: '+674', + flag: '🇳🇷', + flagImage: 'assets/images/flags/nr.png', + nativeName: 'Nauru', + placeholder: '5551234', + }, + { + name: 'Nepal', + code: 'NP', + dialCode: '+977', + flag: '🇳🇵', + flagImage: 'assets/images/flags/np.png', + nativeName: 'नेपाल', + placeholder: '9841234567', + }, + { + name: 'Netherlands', + code: 'NL', + dialCode: '+31', + flag: '🇳🇱', + flagImage: 'assets/images/flags/nl.png', + nativeName: 'Nederland', + placeholder: '0612345678', + }, + { + name: 'New Caledonia', + code: 'NC', + dialCode: '+687', + flag: '🇳🇨', + flagImage: 'assets/images/flags/nc.png', + nativeName: 'Nouvelle-Calédonie', + placeholder: '751234', + }, + { + name: 'New Zealand', + code: 'NZ', + dialCode: '+64', + flag: '🇳🇿', + flagImage: 'assets/images/flags/nz.png', + nativeName: 'New Zealand', + placeholder: '0212345678', + }, + { + name: 'Nicaragua', + code: 'NI', + dialCode: '+505', + flag: '🇳🇮', + flagImage: 'assets/images/flags/ni.png', + nativeName: 'Nicaragua', + placeholder: '81234567', + }, + { + name: 'Niger', + code: 'NE', + dialCode: '+227', + flag: '🇳🇪', + flagImage: 'assets/images/flags/ne.png', + nativeName: 'Nijar', + placeholder: '93123456', + }, + { + name: 'Nigeria', + code: 'NG', + dialCode: '+234', + flag: '🇳🇬', + flagImage: 'assets/images/flags/ng.png', + nativeName: 'Nigeria', + placeholder: '08012345678', + }, + { + name: 'Niue', + code: 'NU', + dialCode: '+683', + flag: '🇳🇺', + flagImage: 'assets/images/flags/nu.png', + nativeName: 'Niue', + placeholder: '1234', + }, + { + name: 'Norfolk Island', + code: 'NF', + dialCode: '+672', + flag: '🇳🇫', + flagImage: 'assets/images/flags/nf.png', + nativeName: 'Norfolk Island', + placeholder: '381234', + }, + { + name: 'North Korea', + code: 'KP', + dialCode: '+850', + flag: '🇰🇵', + flagImage: 'assets/images/flags/kp.png', + nativeName: '조선 민주주의 인민 공화국', + placeholder: '01921234567', + }, + { + name: 'North Macedonia', + code: 'MK', + dialCode: '+389', + flag: '🇲🇰', + flagImage: 'assets/images/flags/mk.png', + nativeName: '+389', + placeholder: '070234567', + }, + { + name: 'Northern Mariana Islands', + code: 'MP', + dialCode: '+1670', + flag: '🇲🇵', + flagImage: 'assets/images/flags/mp.png', + nativeName: 'Northern Mariana Islands', + placeholder: '6702352345', + }, + { + name: 'Norway', + code: 'NO', + dialCode: '+47', + flag: '🇳🇴', + flagImage: 'assets/images/flags/no.png', + nativeName: 'Norge', + placeholder: '40123456', + }, + // O + { + name: 'Oman', + code: 'OM', + dialCode: '+968', + flag: '🇴🇲', + flagImage: 'assets/images/flags/om.png', + nativeName: 'عُمان', + placeholder: '92123456', + }, + // P + { + name: 'Pakistan', + code: 'PK', + dialCode: '+92', + flag: '🇵🇰', + flagImage: 'assets/images/flags/pk.png', + nativeName: 'پاکستان', + placeholder: '03001234567', + }, + { + name: 'Palau', + code: 'PW', + dialCode: '+680', + flag: '🇵🇼', + flagImage: 'assets/images/flags/pw.png', + nativeName: 'Palau', + placeholder: '7701234', + }, + { + name: 'Palestine', + code: 'PS', + dialCode: '+970', + flag: '🇵🇸', + flagImage: 'assets/images/flags/ps.png', + nativeName: 'فلسطين', + placeholder: '0599123456', + }, + { + name: 'Panama', + code: 'PA', + dialCode: '+507', + flag: '🇵🇦', + flagImage: 'assets/images/flags/pa.png', + nativeName: 'Panamá', + placeholder: '61234567', + }, + { + name: 'Papua New Guinea', + code: 'PG', + dialCode: '+675', + flag: '🇵🇬', + flagImage: 'assets/images/flags/pg.png', + nativeName: 'Papua New Guinea', + placeholder: '70123456', + }, + { + name: 'Paraguay', + code: 'PY', + dialCode: '+595', + flag: '🇵🇾', + flagImage: 'assets/images/flags/py.png', + nativeName: 'Paraguay', + placeholder: '0961234567', + }, + { + name: 'Peru', + code: 'PE', + dialCode: '+51', + flag: '🇵🇪', + flagImage: 'assets/images/flags/pe.png', + nativeName: 'Perú', + placeholder: '987654321', + }, + { + name: 'Philippines', + code: 'PH', + dialCode: '+63', + flag: '🇵🇭', + flagImage: 'assets/images/flags/ph.png', + nativeName: 'Philippines', + placeholder: '09171234567', + }, + { + name: 'Pitcairn', + code: 'PN', + dialCode: '+64', + flag: '🇵🇳', + flagImage: 'assets/images/flags/pn.png', + nativeName: 'Pitcairn Islands', + }, + { + name: 'Poland', + code: 'PL', + dialCode: '+48', + flag: '🇵🇱', + flagImage: 'assets/images/flags/pl.png', + nativeName: 'Polska', + placeholder: '501234567', + }, + { + name: 'Portugal', + code: 'PT', + dialCode: '+351', + flag: '🇵🇹', + flagImage: 'assets/images/flags/pt.png', + nativeName: 'Portugal', + placeholder: '912345678', + }, + { + name: 'Puerto Rico', + code: 'PR', + dialCode: '+1', + flag: '🇵🇷', + flagImage: 'assets/images/flags/pr.png', + nativeName: 'Puerto Rico', + placeholder: '7872345678', + }, + // Q + { + name: 'Qatar', + code: 'QA', + dialCode: '+974', + flag: '🇶🇦', + flagImage: 'assets/images/flags/qa.png', + nativeName: 'قطر', + placeholder: '33123456', + }, + // R + { + name: 'Réunion', + code: 'RE', + dialCode: '+262', + flag: '🇫🇷', + flagImage: 'assets/images/flags/mf.png', + nativeName: 'La Réunion', + placeholder: '0692123456', + }, + { + name: 'Romania', + code: 'RO', + dialCode: '+40', + flag: '🇷🇴', + flagImage: 'assets/images/flags/ro.png', + nativeName: 'România', + placeholder: '0712345678', + }, + { + name: 'Russia', + code: 'RU', + dialCode: '+7', + flag: '🇷🇺', + flagImage: 'assets/images/flags/ru.png', + nativeName: 'Россия', + placeholder: '9123456789', + }, + { + name: 'Rwanda', + code: 'RW', + dialCode: '+250', + flag: '🇷🇼', + flagImage: 'assets/images/flags/rw.png', + nativeName: 'Rwanda', + placeholder: '0781234567', + }, + // S + { + name: 'Saint Barthélemy', + code: 'BL', + dialCode: '+590', + flag: '🇫🇷', + flagImage: 'assets/images/flags/fr.png', + nativeName: 'Saint-Barthélemy', + placeholder: '0690001234', + }, + { + name: 'Saint Helena', + code: 'SH', + dialCode: '+290', + flag: '🇸🇭', + flagImage: 'assets/images/flags/sh.png', + nativeName: 'Saint Helena', + placeholder: '62158', + }, + { + name: 'Saint Kitts and Nevis', + code: 'KN', + dialCode: '+1869', + flag: '🇰🇳', + flagImage: 'assets/images/flags/kn.png', + nativeName: 'Saint Kitts and Nevis', + placeholder: '8694651234', + }, + { + name: 'Saint Lucia', + code: 'LC', + dialCode: '+1758', + flag: '🇱🇨', + flagImage: 'assets/images/flags/lc.png', + nativeName: 'Saint Lucia', + placeholder: '7582841234', + }, + { + name: 'Saint Martin (France)', + code: 'MF', + dialCode: '+590', + flag: '🇲🇫', + flagImage: 'assets/images/flags/mf.png', + nativeName: 'Saint-Martin', + placeholder: '0690001234', + }, + { + name: 'Saint Pierre and Miquelon', + code: 'PM', + dialCode: '+508', + flag: '🇫🇷', + flagImage: 'assets/images/flags/fr.png', + nativeName: 'Saint-Pierre-et-Miquelon', + placeholder: '0508123456', + }, + { + name: 'Saint Vincent and the Grenadines', + code: 'VC', + dialCode: '+1784', + flag: '🇻🇨', + flagImage: 'assets/images/flags/vc.png', + nativeName: 'Saint Vincent and the Grenadines', + placeholder: '7844301234', + }, + { + name: 'Samoa', + code: 'WS', + dialCode: '+685', + flag: '🇼🇸', + flagImage: 'assets/images/flags/ws.png', + nativeName: 'Samoa', + placeholder: '7212345', + }, + { + name: 'San Marino', + code: 'SM', + dialCode: '+378', + flag: '🇸🇲', + flagImage: 'assets/images/flags/sm.png', + nativeName: 'San Marino', + placeholder: '66661234', + }, + { + name: 'São Tomé and Príncipe', + code: 'ST', + dialCode: '+239', + flag: '🇸🇹', + flagImage: 'assets/images/flags/st.png', + nativeName: 'São Tomé e Príncipe', + placeholder: '9812345', + }, + { + name: 'Saudi Arabia', + code: 'SA', + dialCode: '+966', + flag: '🇸🇦', + flagImage: 'assets/images/flags/sa.png', + nativeName: 'المملكة العربية السعودية', + placeholder: '501234567', + }, + { + name: 'Senegal', + code: 'SN', + dialCode: '+221', + flag: '🇸🇳', + flagImage: 'assets/images/flags/sn.png', + nativeName: 'Sénégal', + placeholder: '701234567', + }, + { + name: 'Serbia', + code: 'RS', + dialCode: '+381', + flag: '🇷🇸', + flagImage: 'assets/images/flags/rs.png', + nativeName: 'Србија', + placeholder: '0601234567', + }, + { + name: 'Seychelles', + code: 'SC', + dialCode: '+248', + flag: '🇸🇨', + flagImage: 'assets/images/flags/sc.png', + nativeName: 'Seychelles', + placeholder: '2512345', + }, + { + name: 'Sierra Leone', + code: 'SL', + dialCode: '+232', + flag: '🇸🇱', + flagImage: 'assets/images/flags/sl.png', + nativeName: 'Sierra Leone', + placeholder: '076123456', + }, + { + name: 'Singapore', + code: 'SG', + dialCode: '+65', + flag: '🇸🇬', + flagImage: 'assets/images/flags/sg.png', + nativeName: 'Singapore', + placeholder: '81234567', + }, + { + name: 'Sint Maarten', + code: 'SX', + dialCode: '+1721', + flag: '🇸🇽', + flagImage: 'assets/images/flags/sx.png', + nativeName: 'Sint Maarten', + placeholder: '7215201234', + }, + { + name: 'Slovakia', + code: 'SK', + dialCode: '+421', + flag: '🇸🇰', + flagImage: 'assets/images/flags/sk.png', + nativeName: 'Slovensko', + placeholder: '0912123456', + }, + { + name: 'Slovenia', + code: 'SI', + dialCode: '+386', + flag: '🇸🇮', + flagImage: 'assets/images/flags/si.png', + nativeName: 'Slovenija', + placeholder: '031234567', + }, + { + name: 'Solomon Islands', + code: 'SB', + dialCode: '+677', + flag: '🇸🇧', + flagImage: 'assets/images/flags/sb.png', + nativeName: 'Solomon Islands', + placeholder: '7412345', + }, + { + name: 'Somalia', + code: 'SO', + dialCode: '+252', + flag: '🇸🇴', + flagImage: 'assets/images/flags/so.png', + nativeName: 'Soomaaliya', + placeholder: '0612345678', + }, + { + name: 'South Africa', + code: 'ZA', + dialCode: '+27', + flag: '🇿🇦', + flagImage: 'assets/images/flags/za.png', + nativeName: 'South Africa', + placeholder: '0712345678', + }, + { + name: 'South Korea', + code: 'KR', + dialCode: '+82', + flag: '🇰🇷', + flagImage: 'assets/images/flags/kr.png', + nativeName: '대한민국', + placeholder: '01012345678', + }, + { + name: 'South Sudan', + code: 'SS', + dialCode: '+211', + flag: '🇸🇸', + flagImage: 'assets/images/flags/ss.png', + nativeName: 'جنوب السودان', + placeholder: '0977123456', + }, + { + name: 'Spain', + code: 'ES', + dialCode: '+34', + flag: '🇪🇸', + flagImage: 'assets/images/flags/es.png', + nativeName: 'España', + placeholder: '612345678', + }, + { + name: 'Sri Lanka', + code: 'LK', + dialCode: '+94', + flag: '🇱🇰', + flagImage: 'assets/images/flags/lk.png', + nativeName: 'ශ්‍රී ලංකාව', + placeholder: '0712345678', + }, + { + name: 'Sudan', + code: 'SD', + dialCode: '+249', + flag: '🇸🇩', + flagImage: 'assets/images/flags/sd.png', + nativeName: 'السودان', + placeholder: '0912345678', + }, + { + name: 'Suriname', + code: 'SR', + dialCode: '+597', + flag: '🇸🇷', + flagImage: 'assets/images/flags/sr.png', + nativeName: 'Suriname', + placeholder: '7412345', + }, + { + name: 'Svalbard and Jan Mayen', + code: 'SJ', + dialCode: '+47', + flag: '🇸🇯', + flagImage: 'assets/images/flags/sj.png', + nativeName: 'Svalbard og Jan Mayen', + placeholder: '79912345', + }, + { + name: 'Sweden', + code: 'SE', + dialCode: '+46', + flag: '🇸🇪', + flagImage: 'assets/images/flags/se.png', + nativeName: 'Sverige', + placeholder: '0701234567', + }, + { + name: 'Switzerland', + code: 'CH', + dialCode: '+41', + flag: '🇨🇭', + flagImage: 'assets/images/flags/ch.png', + nativeName: 'Schweiz', + placeholder: '0791234567', + }, + { + name: 'Syria', + code: 'SY', + dialCode: '+963', + flag: '🇸🇾', + flagImage: 'assets/images/flags/sy.png', + nativeName: 'سوريا', + placeholder: '0944567890', + }, + // T + { + name: 'Taiwan', + code: 'TW', + dialCode: '+886', + flag: '🇹🇼', + flagImage: 'assets/images/flags/tw.png', + nativeName: '台灣', + placeholder: '0912345678', + }, + { + name: 'Tajikistan', + code: 'TJ', + dialCode: '+992', + flag: '🇹🇯', + flagImage: 'assets/images/flags/tj.png', + nativeName: 'Tajikistan', + placeholder: '917123456', + }, + { + name: 'Tanzania', + code: 'TZ', + dialCode: '+255', + flag: '🇹🇿', + flagImage: 'assets/images/flags/tz.png', + nativeName: 'Tanzania', + placeholder: '0712345678', + }, + { + name: 'Thailand', + code: 'TH', + dialCode: '+66', + flag: '🇹🇭', + flagImage: 'assets/images/flags/th.png', + nativeName: 'ไทย', + placeholder: '0812345678', + }, + { + name: 'Timor-Leste', + code: 'TL', + dialCode: '+670', + flag: '🇹🇱', + flagImage: 'assets/images/flags/tl.png', + nativeName: 'Timor-Leste', + placeholder: '77212345', + }, + { + name: 'Togo', + code: 'TG', + dialCode: '+228', + flag: '🇹🇬', + flagImage: 'assets/images/flags/tg.png', + nativeName: 'Togo', + placeholder: '90112345', + }, + { + name: 'Tokelau', + code: 'TK', + dialCode: '+690', + flag: '🇹🇰', + flagImage: 'assets/images/flags/tk.png', + nativeName: 'Tokelau', + }, + { + name: 'Tonga', + code: 'TO', + dialCode: '+676', + flag: '🇹🇴', + flagImage: 'assets/images/flags/to.png', + nativeName: 'Tonga', + placeholder: '7715123', + }, + { + name: 'Trinidad and Tobago', + code: 'TT', + dialCode: '+1868', + flag: '🇹🇹', + flagImage: 'assets/images/flags/tt.png', + nativeName: 'Trinidad and Tobago', + placeholder: '8682911234', + }, + { + name: 'Tunisia', + code: 'TN', + dialCode: '+216', + flag: '🇹🇳', + flagImage: 'assets/images/flags/tn.png', + nativeName: 'تونس', + placeholder: '20123456', + }, + { + name: 'Turkey', + code: 'TR', + dialCode: '+90', + flag: '🇹🇷', + flagImage: 'assets/images/flags/tr.png', + nativeName: 'Türkiye', + placeholder: '5321234567', + }, + { + name: 'Turkmenistan', + code: 'TM', + dialCode: '+993', + flag: '🇹🇲', + flagImage: 'assets/images/flags/tm.png', + nativeName: 'Turkmenistan', + placeholder: '65123456', + }, + { + name: 'Turks and Caicos Islands', + code: 'TC', + dialCode: '+1649', + flag: '🇹🇨', + flagImage: 'assets/images/flags/tc.png', + nativeName: 'Turks and Caicos Islands', + placeholder: '6493311234', + }, + { + name: 'Tuvalu', + code: 'TV', + dialCode: '+688', + flag: '🇹🇻', + flagImage: 'assets/images/flags/tv.png', + nativeName: 'Tuvalu', + placeholder: '901234', + }, + // U + { + name: 'Uganda', + code: 'UG', + dialCode: '+256', + flag: '🇺🇬', + flagImage: 'assets/images/flags/ug.png', + nativeName: 'Uganda', + placeholder: '0712345678', + }, + { + name: 'Ukraine', + code: 'UA', + dialCode: '+380', + flag: '🇺🇦', + flagImage: 'assets/images/flags/ua.png', + nativeName: 'Україна', + placeholder: '0671234567', + }, + { + name: 'United Arab Emirates', + code: 'AE', + dialCode: '+971', + flag: '🇦🇪', + flagImage: 'assets/images/flags/ae.png', + nativeName: 'الإمارات العربية المتحدة', + placeholder: '0501234567', + }, + // { // Move this in top + // name: 'United Kingdom' + // code: 'GB' + // dialCode: '+44' + // flag: '🇬🇧' + // flagImage: 'assets/images/flags/gb.png' + // nativeName: '+44', + // + // + // + // + // }, + // { // Move this in top + // name: 'United States' + // code: 'US' + // dialCode: '+1' + // flag: '🇺🇸' + // flagImage: 'assets/images/flags/us.png' + // nativeName: '+1', + // + // + // + // + // }, + { + name: 'Uruguay', + code: 'UY', + dialCode: '+598', + flag: '🇺🇾', + flagImage: 'assets/images/flags/uy.png', + nativeName: 'Uruguay', + placeholder: '094231234', + }, + { + name: 'US Virgin Islands', + code: 'VI', + dialCode: '+1340', + flag: '🇻🇮', + flagImage: 'assets/images/flags/vi.png', + nativeName: 'U.S. Virgin Islands', + placeholder: '3403411234', + }, + { + name: 'Uzbekistan', + code: 'UZ', + dialCode: '+998', + flag: '🇺🇿', + flagImage: 'assets/images/flags/uz.png', + nativeName: 'Oʻzbekiston', + placeholder: '901234567', + }, + // V + { + name: 'Vanuatu', + code: 'VU', + dialCode: '+678', + flag: '🇻🇺', + flagImage: 'assets/images/flags/vu.png', + nativeName: 'Vanuatu', + placeholder: '5912345', + }, + { + name: 'Vatican City', + code: 'VA', + dialCode: '+379', // Old +39 + flag: '🇻🇦', + flagImage: 'assets/images/flags/va.png', + nativeName: 'Città del Vaticano', + placeholder: '3451234', + }, + { + name: 'Venezuela', + code: 'VE', + dialCode: '+58', + flag: '🇻🇪', + flagImage: 'assets/images/flags/ve.png', + nativeName: 'Venezuela', + placeholder: '4121234567', + }, + { + name: 'Vietnam', + code: 'VN', + dialCode: '+84', + flag: '🇻🇳', + flagImage: 'assets/images/flags/vn.png', + nativeName: 'Việt Nam', + placeholder: '0912345678', + }, + // W + { + name: 'Wallis and Futuna', + code: 'WF', + dialCode: '+681', + flag: '🇫🇷', + flagImage: 'assets/images/flags/fr.png', + nativeName: 'Wallis-et-Futuna', + placeholder: '501234', + }, + { + name: 'Western Sahara', + code: 'EH', + dialCode: '+212', + flag: '🇪🇭', + flagImage: 'assets/images/flags/eh.png', + nativeName: 'الصحراء الغربية', + placeholder: '0612345678', + }, + // Y + { + name: 'Yemen', + code: 'YE', + dialCode: '+967', + flag: '🇾🇪', + flagImage: 'assets/images/flags/ye.png', + nativeName: 'اليمن', + placeholder: '0712345678', + }, + // Z + { + name: 'Zambia', + code: 'ZM', + dialCode: '+260', + flag: '🇿🇲', + flagImage: 'assets/images/flags/zm.png', + nativeName: 'Zambia', + placeholder: '0971234567', + }, + { + name: 'Zimbabwe', + code: 'ZW', + dialCode: '+263', + flag: '🇿🇼', + flagImage: 'assets/images/flags/zw.png', + nativeName: 'Zimbabwe', + placeholder: '0712345678', + }, +]; diff --git a/libs/services/proxy/users/src/lib/services-proxy-users.module.ts b/libs/services/proxy/users/src/lib/services-proxy-users.module.ts index dd68c503..6294dc44 100644 --- a/libs/services/proxy/users/src/lib/services-proxy-users.module.ts +++ b/libs/services/proxy/users/src/lib/services-proxy-users.module.ts @@ -98,4 +98,20 @@ export class UsersService { public exchangeToken(code: string): Observable<{ token: string }> { return this.httpNoAuth.post<{ token: string }>(UsersUrl.exchangeToken(this.baseURL), { code }, this.options); } + + public emailLogin(email: string, password: string): Observable { + return this.httpNoAuth.post(UsersUrl.emailLogin(this.baseURL), { email, password }, this.options); + } + + public submitOnboarding( + payload: { name: string; mobile: string; organization_name: string }, + authToken?: string + ): Observable { + const headers: Record = { ...this.options.headers }; + if (authToken) { + headers['Authorization'] = authToken; + } + const options = { ...this.options, headers }; + return this.httpNoAuth.post(UsersUrl.onboarding(this.baseURL), payload, options); + } } diff --git a/libs/urls/users-urls/src/index.ts b/libs/urls/users-urls/src/index.ts index 21f9368e..825efef3 100644 --- a/libs/urls/users-urls/src/index.ts +++ b/libs/urls/users-urls/src/index.ts @@ -4,6 +4,8 @@ export const UsersUrl = { getUsers: (baseUrl) => createUrl(baseUrl, 'clientUsers'), register: (baseUrl) => createUrl(baseUrl, 'register'), exchangeToken: (baseUrl) => createUrl(baseUrl, 'exchange-token'), + emailLogin: (baseUrl) => createUrl(baseUrl, 'login'), + onboarding: (baseUrl) => createUrl(baseUrl, 'onboarding'), getRoles: (baseUrl) => createUrl(baseUrl, ':referenceId/cRoles'), createRole: (baseUrl) => createUrl(baseUrl, ':referenceId/cRoles'), updateRole: (baseUrl) => createUrl(baseUrl, ':referenceId/cRoles/:id'), From 23e43b096dcc9fb61f3fa4f0d4357bb8052f24ad Mon Sep 17 00:00:00 2001 From: Giddh's Black Tiger Date: Mon, 20 Apr 2026 15:40:09 +0530 Subject: [PATCH 03/16] refactor: rename token param to onboarding_token and enhance password validation - Change query param from 'token' to 'onboarding_token' in onboarding flow - Move onboarding_token from Authorization header to request body - Add passwordStrength validator with 5 requirements: min length, uppercase, lowercase, number, symbol - Replace static password hint with dynamic checklist showing met/unmet requirements - Add visual feedback with checkmarks (teal) for met rules and X marks (gray) for unmet rules --- .../panel/onboarding/onboarding.component.ts | 12 ++-- .../app/website/login/login-page.component.ts | 2 +- .../register/register-page.component.html | 55 ++++++++++++++++++- .../register/register-page.component.ts | 27 +++++++-- .../36-blocks/src/environments/environment.ts | 1 + libs/custom-validator/src/index.ts | 23 ++++++++ .../src/lib/services-proxy-users.module.ts | 17 +++--- 7 files changed, 112 insertions(+), 25 deletions(-) diff --git a/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts index 022fd209..3db255ec 100644 --- a/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts +++ b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts @@ -113,7 +113,7 @@ export class OnboardingComponent implements OnInit, OnDestroy { }); public ngOnInit(): void { - this.pendingJwtToken = this.activatedRoute.snapshot.queryParamMap.get('token'); + this.pendingJwtToken = this.activatedRoute.snapshot.queryParamMap.get('onboarding_token'); } public ngOnDestroy(): void { @@ -150,10 +150,12 @@ export class OnboardingComponent implements OnInit, OnDestroy { const mobileWithDialCode = `${this.selectedCountry.dialCode}${formValue.mobile}`; this.usersService - .submitOnboarding( - { name: formValue.name, mobile: mobileWithDialCode, organization_name: formValue.organizationName }, - this.pendingJwtToken ?? undefined - ) + .submitOnboarding({ + name: formValue.name, + mobile: mobileWithDialCode, + organization_name: formValue.organizationName, + onboarding_token: this.pendingJwtToken ?? undefined, + }) .pipe(take(1), takeUntil(this.destroy$)) .subscribe({ next: (response) => { diff --git a/apps/36-blocks/src/app/website/login/login-page.component.ts b/apps/36-blocks/src/app/website/login/login-page.component.ts index b31472b5..482a1c77 100644 --- a/apps/36-blocks/src/app/website/login/login-page.component.ts +++ b/apps/36-blocks/src/app/website/login/login-page.component.ts @@ -61,7 +61,7 @@ export class LoginPageComponent implements OnInit, AfterViewInit, OnDestroy { .pipe(ofType(logInActions.emailLoginOnboardingPending), takeUntil(this.destroy$)) .subscribe(({ pendingJwtToken }) => { this.loginInProgress.set(false); - this.router.navigate(['/onboarding'], { queryParams: { token: pendingJwtToken } }); + this.router.navigate(['/onboarding'], { queryParams: { onboarding_token: pendingJwtToken } }); }); this.actions$.pipe(ofType(logInActions.emailLoginSuccess), takeUntil(this.destroy$)).subscribe(() => { diff --git a/apps/36-blocks/src/app/website/register/register-page.component.html b/apps/36-blocks/src/app/website/register/register-page.component.html index a34d5eea..dc321ff1 100644 --- a/apps/36-blocks/src/app/website/register/register-page.component.html +++ b/apps/36-blocks/src/app/website/register/register-page.component.html @@ -109,7 +109,7 @@

Check your inbox!

formControlName="password" autocomplete="new-password" placeholder="Min. 8 characters" - aria-describedby="reg-password-error reg-password-hint" + aria-describedby="reg-password-error" [attr.aria-invalid]="getFieldError('password') ? 'true' : null" class="block w-full rounded-sm border bg-[#0d1117] pl-3.5 pr-11 py-2.5 text-sm text-white placeholder:text-[#484f58] transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-teal-400" [class.border-[#21262d]]="!getFieldError('password')" @@ -164,8 +164,57 @@

Check your inbox!

- } @else { -

At least 8 characters.

+ } + + @if ( + registrationFormGroup.get('password')?.dirty || registrationFormGroup.get('password')?.touched + ) { +
    + @for (rule of passwordRules; track rule.key) { +
  • + @if (rule.met) { + + {{ rule.label }} + } @else { + + {{ rule.label }} + } +
  • + } +
} diff --git a/apps/36-blocks/src/app/website/register/register-page.component.ts b/apps/36-blocks/src/app/website/register/register-page.component.ts index 10a804ce..588076d8 100644 --- a/apps/36-blocks/src/app/website/register/register-page.component.ts +++ b/apps/36-blocks/src/app/website/register/register-page.component.ts @@ -1,6 +1,7 @@ import { ChangeDetectionStrategy, Component, inject, OnDestroy, OnInit } from '@angular/core'; import { RouterModule } from '@angular/router'; import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; +import { CustomValidators } from '@proxy/custom-validator'; import { Store } from '@ngrx/store'; import { toSignal } from '@angular/core/rxjs-interop'; import * as registrationActions from '../home/ngrx/actions/registration.action'; @@ -11,6 +12,12 @@ import { selectRegisteredEmail, } from '../home/ngrx/selector/registration.selector'; +export interface PasswordRule { + key: string; + label: string; + met: boolean; +} + @Component({ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'proxy-register-page', @@ -38,7 +45,7 @@ export class RegisterPageComponent implements OnInit, OnDestroy { email: new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.email] }), password: new FormControl('', { nonNullable: true, - validators: [Validators.required, Validators.minLength(8)], + validators: [Validators.required, CustomValidators.passwordStrength()], }), }); @@ -56,6 +63,18 @@ export class RegisterPageComponent implements OnInit, OnDestroy { this.passwordVisible = !this.passwordVisible; } + public get passwordRules(): PasswordRule[] { + const control = this.registrationFormGroup.get('password'); + const value: string = control?.value ?? ''; + return [ + { key: 'minLength', label: 'At least 8 characters', met: value.length >= 8 }, + { key: 'uppercase', label: 'At least one uppercase letter (A–Z)', met: /[A-Z]/.test(value) }, + { key: 'lowercase', label: 'At least one lowercase letter (a–z)', met: /[a-z]/.test(value) }, + { key: 'number', label: 'At least one number (0–9)', met: /[0-9]/.test(value) }, + { key: 'symbol', label: 'At least one symbol (!@#$…)', met: /[^A-Za-z0-9]/.test(value) }, + ]; + } + public getFieldError(fieldName: string): string | null { const control = this.registrationFormGroup.get(fieldName); if (!control || !control.invalid || !control.touched) { @@ -67,11 +86,7 @@ export class RegisterPageComponent implements OnInit, OnDestroy { if (control.errors?.['email']) { return 'Please enter a valid email address.'; } - if (control.errors?.['minlength']) { - const requiredLength = control.errors['minlength'].requiredLength; - return `Must be at least ${requiredLength} characters.`; - } - return 'Invalid value.'; + return null; } public submitRegistration(): void { diff --git a/apps/36-blocks/src/environments/environment.ts b/apps/36-blocks/src/environments/environment.ts index e5a76fc4..5510301c 100644 --- a/apps/36-blocks/src/environments/environment.ts +++ b/apps/36-blocks/src/environments/environment.ts @@ -7,6 +7,7 @@ import { envVariables } from './env-variables'; export const environment = { production: false, env: 'local', + googleClientId: '', proxyServer: 'http://localhost:4200', baseUrl: 'https://apitest.msg91.com/api', ...envVariables, diff --git a/libs/custom-validator/src/index.ts b/libs/custom-validator/src/index.ts index bd8d81a0..52abec83 100644 --- a/libs/custom-validator/src/index.ts +++ b/libs/custom-validator/src/index.ts @@ -495,4 +495,27 @@ export class CustomValidators { return null; }; } + + public static passwordStrength(): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + const value: string = control.value ?? ''; + const errors: ValidationErrors = {}; + if (value.length < 8) { + errors['minLength'] = true; + } + if (!/[A-Z]/.test(value)) { + errors['uppercase'] = true; + } + if (!/[a-z]/.test(value)) { + errors['lowercase'] = true; + } + if (!/[0-9]/.test(value)) { + errors['number'] = true; + } + if (!/[^A-Za-z0-9]/.test(value)) { + errors['symbol'] = true; + } + return Object.keys(errors).length ? errors : null; + }; + } } diff --git a/libs/services/proxy/users/src/lib/services-proxy-users.module.ts b/libs/services/proxy/users/src/lib/services-proxy-users.module.ts index 6294dc44..1cd6d4c0 100644 --- a/libs/services/proxy/users/src/lib/services-proxy-users.module.ts +++ b/libs/services/proxy/users/src/lib/services-proxy-users.module.ts @@ -103,15 +103,12 @@ export class UsersService { return this.httpNoAuth.post(UsersUrl.emailLogin(this.baseURL), { email, password }, this.options); } - public submitOnboarding( - payload: { name: string; mobile: string; organization_name: string }, - authToken?: string - ): Observable { - const headers: Record = { ...this.options.headers }; - if (authToken) { - headers['Authorization'] = authToken; - } - const options = { ...this.options, headers }; - return this.httpNoAuth.post(UsersUrl.onboarding(this.baseURL), payload, options); + public submitOnboarding(payload: { + name: string; + mobile: string; + organization_name: string; + onboarding_token?: string; + }): Observable { + return this.httpNoAuth.post(UsersUrl.onboarding(this.baseURL), payload, this.options); } } From 9bf132777648ca6ff31bdfa621ad22c14731fa7b Mon Sep 17 00:00:00 2001 From: Giddh's Black Tiger Date: Mon, 20 Apr 2026 16:34:11 +0530 Subject: [PATCH 04/16] refactor(auth): add Firebase auth fallback and memory token check in route guard - Add AngularFireAuth dependency to CanActivateRouteGuard - Import map and take operators from rxjs - Check memory token before redirecting when cookie is missing - Add Firebase authState observable as final fallback for authentication - Return UrlTree redirect only if all auth methods fail --- .../src/app/website/home/authguard/index.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/36-blocks/src/app/website/home/authguard/index.ts b/apps/36-blocks/src/app/website/home/authguard/index.ts index 2a4348c8..57431779 100755 --- a/apps/36-blocks/src/app/website/home/authguard/index.ts +++ b/apps/36-blocks/src/app/website/home/authguard/index.ts @@ -2,13 +2,15 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, Router, RouterStateSnapshot, UrlTree } from '@angular/router'; import { AuthService } from '@proxy/services/proxy/auth'; import { CookieService } from 'ngx-cookie-service'; -import { Observable } from 'rxjs'; +import { AngularFireAuth } from '@angular/fire/compat/auth'; +import { Observable, map, take } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class CanActivateRouteGuard { constructor( private cookieService: CookieService, private authService: AuthService, + private afAuth: AngularFireAuth, private router: Router ) {} @@ -21,6 +23,13 @@ export class CanActivateRouteGuard { this.authService.setTokenSync(authToken); return true; } - return this.router.createUrlTree(['']); + const memoryToken = this.authService.getTokenSync(); + if (memoryToken) { + return true; + } + return this.afAuth.authState.pipe( + take(1), + map((user) => (user ? true : this.router.createUrlTree(['']))) + ); } } From cc2504a428d7585e3297912e3f4607b33a25f659 Mon Sep 17 00:00:00 2001 From: Giddh's Black Tiger Date: Tue, 21 Apr 2026 18:31:12 +0530 Subject: [PATCH 05/16] refactor: replace AngularFireAuthGuard with custom CanActivateRouteGuard and update onboarding flow - Remove AngularFireAuthGuard and redirectUnauthorizedTo imports from routing - Replace AngularFireAuthGuard with CanActivateRouteGuard across all routes - Remove ProjectGuard from panel routes canActivate array - Update onboarding query param from 'onboarding_token' to 'token' - Refactor onboarding submission to dispatch login data to store when client settings available - Simplify onboarding success --- apps/36-blocks/src/app/app.routes.ts | 10 ++--- .../src/app/panel/layout/layout.component.ts | 22 +++++++++++ .../panel/onboarding/onboarding.component.ts | 39 +++++++------------ apps/36-blocks/src/app/panel/panel.routes.ts | 7 +--- .../home/ngrx/effects/login.effects.ts | 27 ++++++++----- .../app/website/login/login-page.component.ts | 2 +- ...es-interceptor-error-interceptor.module.ts | 2 + .../src/lib/services-proxy-users.module.ts | 5 +-- 8 files changed, 62 insertions(+), 52 deletions(-) diff --git a/apps/36-blocks/src/app/app.routes.ts b/apps/36-blocks/src/app/app.routes.ts index b5f3a765..da6cd867 100644 --- a/apps/36-blocks/src/app/app.routes.ts +++ b/apps/36-blocks/src/app/app.routes.ts @@ -1,14 +1,12 @@ import { Component, inject } from '@angular/core'; import { Route, Router } from '@angular/router'; -import { AngularFireAuthGuard, redirectUnauthorizedTo } from '@angular/fire/compat/auth-guard'; import { CookieService } from 'ngx-cookie-service'; import { AuthService } from '@proxy/services/proxy/auth'; +import { CanActivateRouteGuard } from './website/home/authguard'; @Component({ template: '', standalone: true }) class NotFoundRedirectComponent {} -const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['login']); - export const appRoutes: Route[] = [ { path: '', @@ -28,15 +26,13 @@ export const appRoutes: Route[] = [ import('./panel/features/create-feature/feature-preview/widget-preview/widget-preview.component').then( (c) => c.WidgetPreviewComponent ), - data: { authGuardPipe: redirectUnauthorizedToLogin }, - canActivate: [AngularFireAuthGuard], + canActivate: [CanActivateRouteGuard], }, { path: 'project', loadComponent: () => import('./panel/create-project/create-project.component').then((c) => c.CreateProjectComponent), - data: { authGuardPipe: redirectUnauthorizedToLogin }, - canActivate: [AngularFireAuthGuard], + canActivate: [CanActivateRouteGuard], }, { path: 'client', diff --git a/apps/36-blocks/src/app/panel/layout/layout.component.ts b/apps/36-blocks/src/app/panel/layout/layout.component.ts index 51a17045..887966e1 100644 --- a/apps/36-blocks/src/app/panel/layout/layout.component.ts +++ b/apps/36-blocks/src/app/panel/layout/layout.component.ts @@ -151,6 +151,28 @@ export class LayoutComponent extends BaseComponent implements OnInit, OnDestroy } }); + this.clientSettings$.pipe(takeUntil(this.destroy$)).subscribe((clientSettings) => { + if (clientSettings?.client) { + this.logInData$.pipe(take(1)).subscribe((existingLoginData) => { + if (!existingLoginData) { + this.store.dispatch( + logInActions.authenticatedAction({ + response: { + uid: String(clientSettings.client.id), + displayName: clientSettings.client.name, + email: clientSettings.client.email, + phoneNumber: clientSettings.client.mobile ?? null, + photoURL: null, + emailVerified: false, + jwtToken: this.authService.getTokenSync(), + }, + }) + ); + } + }); + } + }); + combineLatest([this.logInData$, this.clientSettings$]).subscribe(([loginData, clientSettings]) => { if (loginData && clientSettings) { this.rootService.generateToken({ source: 'chatbot' }).subscribe((res) => { diff --git a/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts index 3db255ec..23e48111 100644 --- a/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts +++ b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts @@ -12,13 +12,10 @@ import { import { ReactiveFormsModule, FormControl, FormGroup, Validators } from '@angular/forms'; import { ScrollingModule } from '@angular/cdk/scrolling'; import { ActivatedRoute, Router } from '@angular/router'; -import { Actions, ofType } from '@ngrx/effects'; -import { Store } from '@ngrx/store'; import { Subject } from 'rxjs'; import { take, takeUntil } from 'rxjs/operators'; import { AuthService } from '@proxy/services/proxy/auth'; import { UsersService } from '@proxy/services/proxy/users'; -import * as logInActions from '../../website/home/ngrx/actions/login.action'; import { COUNTRIES_DATA, Country } from '../../../../../shared/assets/utils/countries-info'; @Component({ @@ -33,8 +30,6 @@ export class OnboardingComponent implements OnInit, OnDestroy { private readonly router = inject(Router); private readonly authService = inject(AuthService); private readonly usersService = inject(UsersService); - private readonly store = inject(Store); - private readonly actions$ = inject(Actions); private readonly destroy$ = new Subject(); public readonly onboardingSubmitting = signal(false); @@ -113,7 +108,7 @@ export class OnboardingComponent implements OnInit, OnDestroy { }); public ngOnInit(): void { - this.pendingJwtToken = this.activatedRoute.snapshot.queryParamMap.get('onboarding_token'); + this.pendingJwtToken = this.activatedRoute.snapshot.queryParamMap.get('token'); } public ngOnDestroy(): void { @@ -147,13 +142,19 @@ export class OnboardingComponent implements OnInit, OnDestroy { this.onboardingError.set(null); this.onboardingSubmitting.set(true); const formValue = this.onboardingFormGroup.getRawValue(); - const mobileWithDialCode = `${this.selectedCountry.dialCode}${formValue.mobile}`; + const dialCodeDigitsOnly = this.selectedCountry.dialCode.replace(/^\+/, ''); + const mobileWithDialCode = `${dialCodeDigitsOnly}${formValue.mobile}`; this.usersService .submitOnboarding({ - name: formValue.name, - mobile: mobileWithDialCode, - organization_name: formValue.organizationName, + user: { + name: formValue.name, + mobile: mobileWithDialCode, + }, + client: { + name: formValue.organizationName, + mobile: mobileWithDialCode, + }, onboarding_token: this.pendingJwtToken ?? undefined, }) .pipe(take(1), takeUntil(this.destroy$)) @@ -163,22 +164,8 @@ export class OnboardingComponent implements OnInit, OnDestroy { if (jwtToken) { this.authService.setTokenSync(jwtToken); } - - this.actions$ - .pipe(ofType(logInActions.authenticatedAction), take(1), takeUntil(this.destroy$)) - .subscribe(() => { - this.onboardingSubmitting.set(false); - this.router.navigate(['/app/features/create']); - }); - - this.actions$ - .pipe(ofType(logInActions.logInActionError), take(1), takeUntil(this.destroy$)) - .subscribe(({ errors }) => { - this.onboardingSubmitting.set(false); - this.onboardingError.set(errors?.join(' ') || 'Something went wrong. Please try again.'); - }); - - this.store.dispatch(logInActions.getUserAction()); + this.onboardingSubmitting.set(false); + this.router.navigate(['/app/features/create']); }, error: (error) => { const errorBody = error?.error; diff --git a/apps/36-blocks/src/app/panel/panel.routes.ts b/apps/36-blocks/src/app/panel/panel.routes.ts index 7541981e..978772d3 100644 --- a/apps/36-blocks/src/app/panel/panel.routes.ts +++ b/apps/36-blocks/src/app/panel/panel.routes.ts @@ -1,9 +1,5 @@ import { Route } from '@angular/router'; -import { redirectUnauthorizedTo } from '@angular/fire/compat/auth-guard'; import { CanActivateRouteGuard } from '../website/home/authguard'; -import { ProjectGuard } from './guard/project.guard'; - -const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['login']); export const panelRoutes: Route[] = [ { @@ -32,7 +28,6 @@ export const panelRoutes: Route[] = [ loadComponent: () => import('./chatbot/chatbot.component').then((c) => c.ChatbotComponent), }, ], - data: { authGuardPipe: redirectUnauthorizedToLogin }, - canActivate: [CanActivateRouteGuard, ProjectGuard], + canActivate: [CanActivateRouteGuard], }, ]; diff --git a/apps/36-blocks/src/app/website/home/ngrx/effects/login.effects.ts b/apps/36-blocks/src/app/website/home/ngrx/effects/login.effects.ts index 6c979fb9..5e777aec 100755 --- a/apps/36-blocks/src/app/website/home/ngrx/effects/login.effects.ts +++ b/apps/36-blocks/src/app/website/home/ngrx/effects/login.effects.ts @@ -2,7 +2,7 @@ import { Injectable, PLATFORM_ID, inject } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { catchError, exhaustMap, map, switchMap, take } from 'rxjs/operators'; -import { from, of } from 'rxjs'; +import { from, of, throwError } from 'rxjs'; import { errorResolver } from '@proxy/models/root-models'; import { AuthService } from '@proxy/services/proxy/auth'; import * as logInActions from '../actions/login.action'; @@ -29,25 +29,34 @@ export class LogInEffects { ofType(logInActions.emailLoginAction), switchMap(({ email, password }) => this.usersService.emailLogin(email, password).pipe( - map((response) => { + switchMap((response) => { + if (response?.hasError) { + const message = + response?.errors?.message || + response?.data?.message || + response?.message || + 'Login failed. Please check your credentials.'; + return throwError(() => message); + } const isOnboardingPending = response?.data?.is_onboarding_pending === true || response?.is_onboarding_pending === true; const jwtToken = response?.data?.token || response?.token || ''; if (isOnboardingPending && jwtToken) { - return logInActions.emailLoginOnboardingPending({ pendingJwtToken: jwtToken }); + return of(logInActions.emailLoginOnboardingPending({ pendingJwtToken: jwtToken })); } if (jwtToken) { this.authService.setTokenSync(jwtToken); } - return logInActions.emailLoginSuccess(); + return of(logInActions.emailLoginSuccess()); }), catchError((error) => { - const errorBody = error?.error; const resolvedMessage = - errorBody?.errors?.message || - errorBody?.data?.message || - errorBody?.message || - 'Login failed. Please check your credentials.'; + typeof error === 'string' + ? error + : error?.errors?.message || + error?.data?.message || + error?.message || + 'Login failed. Please check your credentials.'; return of(logInActions.logInActionError({ errors: errorResolver(resolvedMessage) })); }) ) diff --git a/apps/36-blocks/src/app/website/login/login-page.component.ts b/apps/36-blocks/src/app/website/login/login-page.component.ts index 482a1c77..b31472b5 100644 --- a/apps/36-blocks/src/app/website/login/login-page.component.ts +++ b/apps/36-blocks/src/app/website/login/login-page.component.ts @@ -61,7 +61,7 @@ export class LoginPageComponent implements OnInit, AfterViewInit, OnDestroy { .pipe(ofType(logInActions.emailLoginOnboardingPending), takeUntil(this.destroy$)) .subscribe(({ pendingJwtToken }) => { this.loginInProgress.set(false); - this.router.navigate(['/onboarding'], { queryParams: { onboarding_token: pendingJwtToken } }); + this.router.navigate(['/onboarding'], { queryParams: { token: pendingJwtToken } }); }); this.actions$.pipe(ofType(logInActions.emailLoginSuccess), takeUntil(this.destroy$)).subscribe(() => { diff --git a/libs/services/interceptor/error-interceptor/src/lib/services-interceptor-error-interceptor.module.ts b/libs/services/interceptor/error-interceptor/src/lib/services-interceptor-error-interceptor.module.ts index ec287a49..dde7a26b 100644 --- a/libs/services/interceptor/error-interceptor/src/lib/services-interceptor-error-interceptor.module.ts +++ b/libs/services/interceptor/error-interceptor/src/lib/services-interceptor-error-interceptor.module.ts @@ -21,6 +21,8 @@ export class ErrorInterceptor implements HttpInterceptor { if ( request.url.includes('api/register') || request.url.includes('api/googleLogin') || + request.url.includes('api/login') || + request.url.includes('api/onboarding') || request.url.includes('flow.sokt.io') || this.cookieService.get('authToken') ) { diff --git a/libs/services/proxy/users/src/lib/services-proxy-users.module.ts b/libs/services/proxy/users/src/lib/services-proxy-users.module.ts index 1cd6d4c0..1ea94804 100644 --- a/libs/services/proxy/users/src/lib/services-proxy-users.module.ts +++ b/libs/services/proxy/users/src/lib/services-proxy-users.module.ts @@ -104,9 +104,8 @@ export class UsersService { } public submitOnboarding(payload: { - name: string; - mobile: string; - organization_name: string; + user: { name: string; mobile: string }; + client: { name: string; mobile: string }; onboarding_token?: string; }): Observable { return this.httpNoAuth.post(UsersUrl.onboarding(this.baseURL), payload, this.options); From 35cfae28ed7672e2ba4af1138c644f8a3fdc0b02 Mon Sep 17 00:00:00 2001 From: Giddh's Black Tiger Date: Tue, 21 Apr 2026 18:58:58 +0530 Subject: [PATCH 06/16] refactor: remove ProjectGuard and unused exchangeToken functionality - Delete ProjectGuard file and remove from layout routes canActivate array - Remove redirectUnauthorizedTo and authGuardPipe data from layout routes - Remove exchangeToken method from UsersService - Remove exchangeToken URL definition from users-urls --- .../src/app/panel/guard/project.guard.ts | 41 ------------------- .../src/app/panel/layout/layout.routes.ts | 7 +--- .../src/lib/services-proxy-users.module.ts | 4 -- libs/urls/users-urls/src/index.ts | 1 - 4 files changed, 1 insertion(+), 52 deletions(-) delete mode 100644 apps/36-blocks/src/app/panel/guard/project.guard.ts diff --git a/apps/36-blocks/src/app/panel/guard/project.guard.ts b/apps/36-blocks/src/app/panel/guard/project.guard.ts deleted file mode 100644 index c37548ab..00000000 --- a/apps/36-blocks/src/app/panel/guard/project.guard.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Injectable } from '@angular/core'; -import { UrlTree, Router } from '@angular/router'; -import { Observable, filter } from 'rxjs'; -import { take } from 'rxjs/operators'; -import { rootActions } from '../../core/ngrx/actions'; -import { select, Store } from '@ngrx/store'; -import { IAppState, selectAllProjectList } from '../../core/ngrx'; -import { IPaginatedResponse } from '@proxy/models/root-models'; -import { IProjects } from '@proxy/models/logs-models'; - -@Injectable({ - providedIn: 'root', -}) -export class ProjectGuard { - public getProject$: Observable>; - - constructor( - private router: Router, - private store: Store - ) { - this.getProject$ = this.store.pipe(select(selectAllProjectList)); - } - - canActivate(): Observable | Promise | boolean | UrlTree { - return new Promise((promiseResolve) => { - this.getProject$.pipe(take(1)).subscribe((res) => !res && this.store.dispatch(rootActions.getAllProject())); - this.getProject$ - .pipe( - filter((value) => value != null), - take(1) - ) - .subscribe((res) => { - if (res.data.length === 0) { - this.router.navigate(['/project']); - } else { - promiseResolve(true); - } - }); - }); - } -} diff --git a/apps/36-blocks/src/app/panel/layout/layout.routes.ts b/apps/36-blocks/src/app/panel/layout/layout.routes.ts index eef11cbe..7da8545f 100644 --- a/apps/36-blocks/src/app/panel/layout/layout.routes.ts +++ b/apps/36-blocks/src/app/panel/layout/layout.routes.ts @@ -1,9 +1,5 @@ import { Route } from '@angular/router'; import { CanActivateRouteGuard } from '../../website/home/authguard'; -import { redirectUnauthorizedTo } from '@angular/fire/compat/auth-guard'; -import { ProjectGuard } from '../guard/project.guard'; - -const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['login']); export const layoutRoutes: Route[] = [ { @@ -32,7 +28,6 @@ export const layoutRoutes: Route[] = [ loadComponent: () => import('../chatbot/chatbot.component').then((c) => c.ChatbotComponent), }, ], - data: { authGuardPipe: redirectUnauthorizedToLogin }, - canActivate: [CanActivateRouteGuard, ProjectGuard], + canActivate: [CanActivateRouteGuard], }, ]; diff --git a/libs/services/proxy/users/src/lib/services-proxy-users.module.ts b/libs/services/proxy/users/src/lib/services-proxy-users.module.ts index 1ea94804..0647345f 100644 --- a/libs/services/proxy/users/src/lib/services-proxy-users.module.ts +++ b/libs/services/proxy/users/src/lib/services-proxy-users.module.ts @@ -95,10 +95,6 @@ export class UsersService { return this.httpNoAuth.post(UsersUrl.register(this.baseURL), formData, this.options); } - public exchangeToken(code: string): Observable<{ token: string }> { - return this.httpNoAuth.post<{ token: string }>(UsersUrl.exchangeToken(this.baseURL), { code }, this.options); - } - public emailLogin(email: string, password: string): Observable { return this.httpNoAuth.post(UsersUrl.emailLogin(this.baseURL), { email, password }, this.options); } diff --git a/libs/urls/users-urls/src/index.ts b/libs/urls/users-urls/src/index.ts index 825efef3..aa38052a 100644 --- a/libs/urls/users-urls/src/index.ts +++ b/libs/urls/users-urls/src/index.ts @@ -3,7 +3,6 @@ import { createUrl } from '@proxy/service'; export const UsersUrl = { getUsers: (baseUrl) => createUrl(baseUrl, 'clientUsers'), register: (baseUrl) => createUrl(baseUrl, 'register'), - exchangeToken: (baseUrl) => createUrl(baseUrl, 'exchange-token'), emailLogin: (baseUrl) => createUrl(baseUrl, 'login'), onboarding: (baseUrl) => createUrl(baseUrl, 'onboarding'), getRoles: (baseUrl) => createUrl(baseUrl, ':referenceId/cRoles'), From 0a655c9efe38ff21c3d9bfffa4a9c47d8c5e0144 Mon Sep 17 00:00:00 2001 From: Giddh's Black Tiger Date: Thu, 23 Apr 2026 13:19:45 +0530 Subject: [PATCH 07/16] refactor: update onboarding route path from 'onboarding' to 'app/onboarding' --- apps/36-blocks/src/app/app.routes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/36-blocks/src/app/app.routes.ts b/apps/36-blocks/src/app/app.routes.ts index da6cd867..0135cb50 100644 --- a/apps/36-blocks/src/app/app.routes.ts +++ b/apps/36-blocks/src/app/app.routes.ts @@ -13,7 +13,7 @@ export const appRoutes: Route[] = [ loadChildren: () => import('./website/website.routes').then((r) => r.websiteRoutes), }, { - path: 'onboarding', + path: 'app/onboarding', loadComponent: () => import('./panel/onboarding/onboarding.component').then((c) => c.OnboardingComponent), }, { From 8e64c668313090a7acefbf15aaa5a79d5730655d Mon Sep 17 00:00:00 2001 From: Giddh's Black Tiger Date: Thu, 23 Apr 2026 13:42:34 +0530 Subject: [PATCH 08/16] Cascade snapshot 2026-04-23T08:12:34.013179Z From 77f95ebc607a6ca29a2315eb60b8c52598745881 Mon Sep 17 00:00:00 2001 From: Giddh's Black Tiger Date: Thu, 23 Apr 2026 13:58:44 +0530 Subject: [PATCH 09/16] fix: enforce base href="/" in app shell to prevent incorrect JS chunk loading from /app/ path --- tools/postbuild.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/postbuild.js b/tools/postbuild.js index 2603c8d9..8dde0d23 100644 --- a/tools/postbuild.js +++ b/tools/postbuild.js @@ -82,8 +82,16 @@ readDir(path.join(__dirname, rootDirectiory)) if (!fs.existsSync(appShellDir)) { fs.mkdirSync(appShellDir, { recursive: true }); } - fs.copyFileSync(csrHtmlPath, appShellPath); - console.log(`Copied index.csr.html → app/index.html`); + + let appShellHtml = fs.readFileSync(csrHtmlPath, 'utf8'); + + // Force base href to "/" so JS chunks load from the root, not from /app/ + if (!appShellHtml.includes('')) { + appShellHtml = appShellHtml.replace(//i, ''); + } + + fs.writeFileSync(appShellPath, appShellHtml); + console.log(`Copied index.csr.html → app/index.html (base href enforced)`); } else { console.log('index.csr.html not found, skipping app/index.html copy'); } From 9e1da67d96ebdb936bef42031f77b43faeb19aac Mon Sep 17 00:00:00 2001 From: Giddh's Black Tiger Date: Thu, 23 Apr 2026 16:04:33 +0530 Subject: [PATCH 10/16] Revert "fix: enforce base href="/" in app shell to prevent incorrect JS chunk loading from /app/ path" This reverts commit 77f95ebc607a6ca29a2315eb60b8c52598745881. --- tools/postbuild.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/tools/postbuild.js b/tools/postbuild.js index 8dde0d23..2603c8d9 100644 --- a/tools/postbuild.js +++ b/tools/postbuild.js @@ -82,16 +82,8 @@ readDir(path.join(__dirname, rootDirectiory)) if (!fs.existsSync(appShellDir)) { fs.mkdirSync(appShellDir, { recursive: true }); } - - let appShellHtml = fs.readFileSync(csrHtmlPath, 'utf8'); - - // Force base href to "/" so JS chunks load from the root, not from /app/ - if (!appShellHtml.includes('')) { - appShellHtml = appShellHtml.replace(//i, ''); - } - - fs.writeFileSync(appShellPath, appShellHtml); - console.log(`Copied index.csr.html → app/index.html (base href enforced)`); + fs.copyFileSync(csrHtmlPath, appShellPath); + console.log(`Copied index.csr.html → app/index.html`); } else { console.log('index.csr.html not found, skipping app/index.html copy'); } From 64b28e3c9993ed71ede2298aa5efb4ed70114aca Mon Sep 17 00:00:00 2001 From: Giddh's Black Tiger Date: Thu, 23 Apr 2026 16:16:52 +0530 Subject: [PATCH 11/16] chore: remove SSR/prerender, switch to pure CSR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove server, prerender, ssr from project.json build options - Set all routes to RenderMode.Client in app.routes.server.ts - Strip provideServerRendering from app.config.server.ts - Remove main.server.ts and server.ts from tsconfig.app.json files - Remove @angular/ssr, @angular/platform-server, express, @types/express from package.json - postbuild.js: copy index.html → app/index.html (was index.csr.html), enforce base href --- apps/36-blocks/project.json | 5 ----- apps/36-blocks/src/app/app.config.server.ts | 4 +--- apps/36-blocks/src/app/app.routes.server.ts | 20 ------------------ apps/36-blocks/tsconfig.app.json | 2 +- package.json | 4 ---- tools/postbuild.js | 23 ++++++++++++++------- 6 files changed, 18 insertions(+), 40 deletions(-) diff --git a/apps/36-blocks/project.json b/apps/36-blocks/project.json index ef93ea4c..62a7c035 100644 --- a/apps/36-blocks/project.json +++ b/apps/36-blocks/project.json @@ -19,11 +19,6 @@ "outputPath": "dist/apps/36-blocks", "index": "apps/36-blocks/src/index.html", "browser": "apps/36-blocks/src/main.ts", - "server": "apps/36-blocks/src/main.server.ts", - "prerender": true, - "ssr": { - "entry": "apps/36-blocks/src/server.ts" - }, "polyfills": ["zone.js"], "tsConfig": "apps/36-blocks/tsconfig.app.json", "inlineStyleLanguage": "scss", diff --git a/apps/36-blocks/src/app/app.config.server.ts b/apps/36-blocks/src/app/app.config.server.ts index 307a67f3..0436fd6f 100644 --- a/apps/36-blocks/src/app/app.config.server.ts +++ b/apps/36-blocks/src/app/app.config.server.ts @@ -1,8 +1,6 @@ import { ApplicationConfig } from '@angular/core'; -import { provideServerRendering, withRoutes } from '@angular/ssr'; import { PERSISTENCE } from '@angular/fire/compat/auth'; -import { serverRoutes } from './app.routes.server'; export const config: ApplicationConfig = { - providers: [provideServerRendering(withRoutes(serverRoutes)), { provide: PERSISTENCE, useValue: 'none' }], + providers: [{ provide: PERSISTENCE, useValue: 'none' }], }; diff --git a/apps/36-blocks/src/app/app.routes.server.ts b/apps/36-blocks/src/app/app.routes.server.ts index d8821210..11ea7c52 100644 --- a/apps/36-blocks/src/app/app.routes.server.ts +++ b/apps/36-blocks/src/app/app.routes.server.ts @@ -1,26 +1,6 @@ import { RenderMode, ServerRoute } from '@angular/ssr'; export const serverRoutes: ServerRoute[] = [ - { - path: '', - renderMode: RenderMode.Prerender, - }, - { - path: 'app/**', - renderMode: RenderMode.Client, - }, - { - path: 'widget-preview/**', - renderMode: RenderMode.Client, - }, - { - path: 'project', - renderMode: RenderMode.Client, - }, - { - path: 'client/**', - renderMode: RenderMode.Client, - }, { path: '**', renderMode: RenderMode.Client, diff --git a/apps/36-blocks/tsconfig.app.json b/apps/36-blocks/tsconfig.app.json index 04923602..dbbf8ab4 100644 --- a/apps/36-blocks/tsconfig.app.json +++ b/apps/36-blocks/tsconfig.app.json @@ -4,7 +4,7 @@ "outDir": "../../dist/out-tsc", "types": ["node"] }, - "files": ["src/main.ts", "src/main.server.ts", "src/server.ts"], + "files": ["src/main.ts"], "include": ["src/**/*.d.ts"], "exclude": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts"] } diff --git a/package.json b/package.json index a820ad81..0959de66 100755 --- a/package.json +++ b/package.json @@ -67,9 +67,7 @@ "@angular/material-moment-adapter": "21.2.2", "@angular/platform-browser": "21.2.4", "@angular/platform-browser-dynamic": "21.2.4", - "@angular/platform-server": "^21.2.4", "@angular/router": "21.2.4", - "@angular/ssr": "^21.2.2", "@highcharts/map-collection": "2.0.1", "@materia-ui/ngx-monaco-editor": "6.0.0", "@ngrx/component": "21.0.1", @@ -100,7 +98,6 @@ "d3-transition": "3.0.1", "dayjs": "1.11.7", "echarts": "^6.0.0", - "express": "^5.2.1", "firebase": "^12.10.0", "froala-editor": "4.0.15", "fs-extra": "5.0.0", @@ -147,7 +144,6 @@ "@nx/workspace": "21.6.10", "@schematics/angular": "21.2.2", "@types/chart.js": "^2.9.28", - "@types/express": "^5.0.6", "@types/jest": "29.5.14", "@types/lodash": "^4.14.161", "@types/lodash-es": "^4.17.3", diff --git a/tools/postbuild.js b/tools/postbuild.js index 2603c8d9..dde85448 100644 --- a/tools/postbuild.js +++ b/tools/postbuild.js @@ -72,20 +72,29 @@ readDir(path.join(__dirname, rootDirectiory)) }); }) .then(() => { - // Copy index.csr.html → app/index.html so static hosts (Amplify, S3, Nginx) - // can route /app/* to a clean Angular shell instead of the prerendered home page. - const csrHtmlPath = path.join(__dirname, rootDirectiory, 'index.csr.html'); + // Copy index.html → app/index.html so static hosts (Amplify, S3, Nginx) + // can route /app/* to the CSR Angular shell. + // With SSR/prerender disabled the build outputs index.html directly (no index.csr.html). + const distIndexPath = path.join(__dirname, rootDirectiory, 'index.html'); const appShellDir = path.join(__dirname, rootDirectiory, 'app'); const appShellPath = path.join(appShellDir, 'index.html'); - if (fs.existsSync(csrHtmlPath)) { + if (fs.existsSync(distIndexPath)) { if (!fs.existsSync(appShellDir)) { fs.mkdirSync(appShellDir, { recursive: true }); } - fs.copyFileSync(csrHtmlPath, appShellPath); - console.log(`Copied index.csr.html → app/index.html`); + + let appShellHtml = fs.readFileSync(distIndexPath, 'utf8'); + + // Force base href to "/" so JS chunks load from the root, not from /app/ + if (!appShellHtml.includes('')) { + appShellHtml = appShellHtml.replace(//i, ''); + } + + fs.writeFileSync(appShellPath, appShellHtml); + console.log(`Copied index.html → app/index.html (base href enforced)`); } else { - console.log('index.csr.html not found, skipping app/index.html copy'); + console.log('index.html not found, skipping app/index.html copy'); } }) .catch((err) => { From d7411500dd5c495ee4db0a7aec5b59b2697188ac Mon Sep 17 00:00:00 2001 From: Divyanshu Shrivastava <69809432+dvCodeWorld@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:39:19 +0530 Subject: [PATCH 12/16] Revert path change on /onboarding --- apps/36-blocks/src/app/app.routes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/36-blocks/src/app/app.routes.ts b/apps/36-blocks/src/app/app.routes.ts index 0135cb50..da6cd867 100644 --- a/apps/36-blocks/src/app/app.routes.ts +++ b/apps/36-blocks/src/app/app.routes.ts @@ -13,7 +13,7 @@ export const appRoutes: Route[] = [ loadChildren: () => import('./website/website.routes').then((r) => r.websiteRoutes), }, { - path: 'app/onboarding', + path: 'onboarding', loadComponent: () => import('./panel/onboarding/onboarding.component').then((c) => c.OnboardingComponent), }, { From d90c5739432c760308b9d75a90da21d3a0a0049c Mon Sep 17 00:00:00 2001 From: Giddh's Black Tiger Date: Thu, 23 Apr 2026 17:07:32 +0530 Subject: [PATCH 13/16] refactor: remove app/index.html copy logic from postbuild script - Remove code that copies index.html to app/index.html directory - Remove base href enforcement logic for app shell - Simplify postbuild completion logging --- tools/postbuild.js | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/tools/postbuild.js b/tools/postbuild.js index 2603c8d9..09e8281e 100644 --- a/tools/postbuild.js +++ b/tools/postbuild.js @@ -72,21 +72,7 @@ readDir(path.join(__dirname, rootDirectiory)) }); }) .then(() => { - // Copy index.csr.html → app/index.html so static hosts (Amplify, S3, Nginx) - // can route /app/* to a clean Angular shell instead of the prerendered home page. - const csrHtmlPath = path.join(__dirname, rootDirectiory, 'index.csr.html'); - const appShellDir = path.join(__dirname, rootDirectiory, 'app'); - const appShellPath = path.join(appShellDir, 'index.html'); - - if (fs.existsSync(csrHtmlPath)) { - if (!fs.existsSync(appShellDir)) { - fs.mkdirSync(appShellDir, { recursive: true }); - } - fs.copyFileSync(csrHtmlPath, appShellPath); - console.log(`Copied index.csr.html → app/index.html`); - } else { - console.log('index.csr.html not found, skipping app/index.html copy'); - } + console.log('Post-build tasks complete'); }) .catch((err) => { console.log('Error with post build:', err); From 61c746a9c82f69aee5e5b7cab46cc6f63c026c4a Mon Sep 17 00:00:00 2001 From: prakharlowanshi Date: Mon, 27 Apr 2026 16:35:13 +0530 Subject: [PATCH 14/16] feat: enhance dashboard card value retrieval with fallback option --- .../src/app/panel/dashboard/dashboard.component.html | 2 +- .../src/app/panel/dashboard/dashboard.component.ts | 10 ++++++++-- .../src/app/panel/dashboard/dashboard.models.ts | 4 +++- .../src/app/panel/onboarding/onboarding.component.ts | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/36-blocks/src/app/panel/dashboard/dashboard.component.html b/apps/36-blocks/src/app/panel/dashboard/dashboard.component.html index c42a74e9..8ca577c1 100644 --- a/apps/36-blocks/src/app/panel/dashboard/dashboard.component.html +++ b/apps/36-blocks/src/app/panel/dashboard/dashboard.component.html @@ -78,7 +78,7 @@

Analytics Overview

>

- {{ getCardValue(overviewData(), card.valueKey) | number }} + {{ getCardValue(overviewData(), card.valueKey, card.valueKeyFallback) | number }}

{{ card.sub }} diff --git a/apps/36-blocks/src/app/panel/dashboard/dashboard.component.ts b/apps/36-blocks/src/app/panel/dashboard/dashboard.component.ts index 3a2847db..780a87ab 100644 --- a/apps/36-blocks/src/app/panel/dashboard/dashboard.component.ts +++ b/apps/36-blocks/src/app/panel/dashboard/dashboard.component.ts @@ -70,8 +70,14 @@ export class DashboardComponent extends BaseComponent implements OnInit { readonly overviewCards = OVERVIEW_CARDS; - getCardValue(data: any, path: string): number { - return path.split('.').reduce((acc, k) => acc?.[k], data) ?? 0; + getCardValue(data: any, path: string, fallbackPath?: string): number { + const read = (p: string) => p.split('.').reduce((acc, k) => acc?.[k], data); + const primary = read(path); + if (fallbackPath) { + if (primary) return primary as number; + return (read(fallbackPath) as number) ?? 0; + } + return (primary as number) ?? 0; } readonly rangeOptions = RANGE_OPTIONS; diff --git a/apps/36-blocks/src/app/panel/dashboard/dashboard.models.ts b/apps/36-blocks/src/app/panel/dashboard/dashboard.models.ts index 0c59c191..5c1ae0de 100644 --- a/apps/36-blocks/src/app/panel/dashboard/dashboard.models.ts +++ b/apps/36-blocks/src/app/panel/dashboard/dashboard.models.ts @@ -33,6 +33,7 @@ export interface IRangeOption { export interface IOverviewCard { key: string; valueKey: string; + valueKeyFallback?: string; label: string; icon: string; sub: string; @@ -85,7 +86,8 @@ export interface IBreakdownGroupByOption { export const OVERVIEW_CARDS: IOverviewCard[] = [ { key: 'users', - valueKey: 'users.client_total', + valueKey: 'users.feature_configuration_total', + valueKeyFallback: 'users.client_total', label: 'Total Users', icon: 'people', sub: 'registered total', diff --git a/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts index 23e48111..f317cc69 100644 --- a/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts +++ b/apps/36-blocks/src/app/panel/onboarding/onboarding.component.ts @@ -108,7 +108,7 @@ export class OnboardingComponent implements OnInit, OnDestroy { }); public ngOnInit(): void { - this.pendingJwtToken = this.activatedRoute.snapshot.queryParamMap.get('token'); + this.pendingJwtToken = this.activatedRoute.snapshot.queryParamMap.get('onboarding_token'); } public ngOnDestroy(): void { From 97db1f3d7888b76087d0cff09f8e0526580ec19b Mon Sep 17 00:00:00 2001 From: prakharlowanshi Date: Fri, 1 May 2026 13:18:27 +0530 Subject: [PATCH 15/16] fix the redirection issue --- .../create-feature/create-feature.component.html | 8 +++++--- .../create-feature/create-feature.component.ts | 2 ++ .../src/app/panel/layout/layout.component.html | 5 +---- .../website/layout/website-layout.component.html | 3 ++- .../app/website/layout/website-layout.component.ts | 13 +++++++++++++ .../app/website/register/register-page.component.ts | 11 ++++++++++- 6 files changed, 33 insertions(+), 9 deletions(-) diff --git a/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.html b/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.html index 61f97e62..ebc806d6 100644 --- a/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.html +++ b/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.html @@ -3,9 +3,11 @@ }
- + @if (!sideNavService.hideSidebar()) { + + } @if (isEditMode) {
@if (nameFieldEditMode) { diff --git a/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.ts b/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.ts index adeb583e..cae4597d 100644 --- a/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.ts +++ b/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.ts @@ -68,6 +68,7 @@ import { CreateTaxDialogComponent } from './create-tax-dialog/create-tax-dialog. import { ConfirmDialogComponent } from '@proxy/ui/confirm-dialog'; import { ServiceListComponent, ServiceListItem } from '@proxy/ui/service-list'; import { UiSettingsService } from '../../layout/ui-settings.service'; +import { SideNavService } from '../../layout/side-nav.service'; import { WidgetThemeService } from 'apps/36-blocks-widget/src/app/otp/service/widget-theme.service'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { FeaturePreviewComponent } from './feature-preview/feature-preview.component'; @@ -160,6 +161,7 @@ export class CreateFeatureComponent extends BaseComponent implements OnDestroy, private http = inject(HttpClient); private uiSettings = inject(UiSettingsService); private themeService = inject(WidgetThemeService); + public readonly sideNavService = inject(SideNavService); public taxes: any[] = []; public createPlanForm: any; diff --git a/apps/36-blocks/src/app/panel/layout/layout.component.html b/apps/36-blocks/src/app/panel/layout/layout.component.html index ce152ce8..7eee5b64 100644 --- a/apps/36-blocks/src/app/panel/layout/layout.component.html +++ b/apps/36-blocks/src/app/panel/layout/layout.component.html @@ -72,10 +72,7 @@
- + @if (logInData$ | async; as user) {
diff --git a/apps/36-blocks/src/app/website/layout/website-layout.component.ts b/apps/36-blocks/src/app/website/layout/website-layout.component.ts index dcac07ee..39951844 100644 --- a/apps/36-blocks/src/app/website/layout/website-layout.component.ts +++ b/apps/36-blocks/src/app/website/layout/website-layout.component.ts @@ -5,6 +5,7 @@ import { filter, map, startWith } from 'rxjs/operators'; import { toSignal } from '@angular/core/rxjs-interop'; import { Store } from '@ngrx/store'; import * as logInActions from '../home/ngrx/actions/login.action'; +import * as registrationActions from '../home/ngrx/actions/registration.action'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -77,4 +78,16 @@ export class WebsiteLayoutComponent implements OnInit, OnDestroy { this.closeMobileMenu(); this.store.dispatch(logInActions.logInAction()); } + + /** + * routerLink to /register is a no-op when already on /register, so the register page + * never re-initializes and the post-sign-up banner stays visible. Reset registration + * state so the form shows again. + */ + public onRegisterCtaClick(): void { + const path = this.router.url.split('?')[0].split('#')[0]; + if (path === '/register') { + this.store.dispatch(registrationActions.registrationResetAction()); + } + } } diff --git a/apps/36-blocks/src/app/website/register/register-page.component.ts b/apps/36-blocks/src/app/website/register/register-page.component.ts index 588076d8..d6add61e 100644 --- a/apps/36-blocks/src/app/website/register/register-page.component.ts +++ b/apps/36-blocks/src/app/website/register/register-page.component.ts @@ -3,7 +3,8 @@ import { RouterModule } from '@angular/router'; import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; import { CustomValidators } from '@proxy/custom-validator'; import { Store } from '@ngrx/store'; -import { toSignal } from '@angular/core/rxjs-interop'; +import { Actions, ofType } from '@ngrx/effects'; +import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; import * as registrationActions from '../home/ngrx/actions/registration.action'; import { selectRegistrationInProgress, @@ -27,6 +28,7 @@ export interface PasswordRule { }) export class RegisterPageComponent implements OnInit, OnDestroy { private readonly store = inject(Store); + private readonly actions$ = inject(Actions); public readonly registrationInProgress = toSignal(this.store.select(selectRegistrationInProgress), { initialValue: false, @@ -51,6 +53,13 @@ export class RegisterPageComponent implements OnInit, OnDestroy { public passwordVisible = false; + public constructor() { + this.actions$.pipe(ofType(registrationActions.registrationResetAction), takeUntilDestroyed()).subscribe(() => { + this.registrationFormGroup.reset({ email: '', password: '' }); + this.passwordVisible = false; + }); + } + public ngOnInit(): void { this.store.dispatch(registrationActions.registrationResetAction()); } From 01576a5a0257e1dcd8abf3f06f3866b3849de111 Mon Sep 17 00:00:00 2001 From: prakharlowanshi Date: Mon, 4 May 2026 16:39:43 +0530 Subject: [PATCH 16/16] user management inside the block --- .../create-feature.component.html | 28 +++++- .../create-feature.component.ts | 6 ++ .../management/management.component.html | 4 +- .../users/management/management.component.ts | 85 ++++++++++++------- 4 files changed, 88 insertions(+), 35 deletions(-) diff --git a/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.html b/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.html index ebc806d6..a613af8e 100644 --- a/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.html +++ b/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.html @@ -302,7 +302,11 @@

Add New Block

@if (isEditMode) {
- +
@if (featureForm.get('primaryDetails.feature_id')?.value === 1) { @@ -439,11 +443,18 @@

Add New Block

+ +
+ +
+
-
- -
+ @if (editModeMainTabIndex !== editModeManageMembersTabIndex) { +
+ +
+ }
}
@@ -1193,6 +1204,15 @@

+
+
+ +
+
+

+
diff --git a/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.ts b/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.ts index cae4597d..67228a3a 100644 --- a/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.ts +++ b/apps/36-blocks/src/app/panel/features/create-feature/create-feature.component.ts @@ -67,6 +67,7 @@ import { CreatePlanDialogComponent } from './create-plan-dialog/create-plan-dial import { CreateTaxDialogComponent } from './create-tax-dialog/create-tax-dialog.component'; import { ConfirmDialogComponent } from '@proxy/ui/confirm-dialog'; import { ServiceListComponent, ServiceListItem } from '@proxy/ui/service-list'; +import { ManagementComponent } from '../../users/management/management.component'; import { UiSettingsService } from '../../layout/ui-settings.service'; import { SideNavService } from '../../layout/side-nav.service'; import { WidgetThemeService } from 'apps/36-blocks-widget/src/app/otp/service/widget-theme.service'; @@ -140,6 +141,7 @@ export interface PeriodicElement { ServiceListComponent, MatButtonToggleModule, FeaturePreviewComponent, + ManagementComponent, ], templateUrl: './create-feature.component.html', styleUrls: ['./create-feature.component.scss'], @@ -222,6 +224,10 @@ export class CreateFeatureComponent extends BaseComponent implements OnDestroy, public uploadLogoUrl$: Observable = this.componentStore.uploadLogoUrl$; public errorInUploadLogo$: Observable = this.componentStore.errorInUploadLogo$; public isEditMode = false; + /** Selected index of the edit-mode tab group; used to hide the preview panel on Manage Members. */ + public editModeMainTabIndex = 0; + /** Manage Members tab index: Service, Branding, Setting, Design & code, Webhook, Manage Members. */ + public readonly editModeManageMembersTabIndex = 5; public previewInputPosition: 'top' | 'bottom' = 'top'; public selectedServiceIndex = 0; public selectedSubscriptionServiceIndex = -2; diff --git a/apps/36-blocks/src/app/panel/users/management/management.component.html b/apps/36-blocks/src/app/panel/users/management/management.component.html index dfcdc418..02e717ef 100644 --- a/apps/36-blocks/src/app/panel/users/management/management.component.html +++ b/apps/36-blocks/src/app/panel/users/management/management.component.html @@ -1,5 +1,5 @@
- + @if (!roleForm.get('feature_id')?.value) {
diff --git a/apps/36-blocks/src/app/panel/users/management/management.component.ts b/apps/36-blocks/src/app/panel/users/management/management.component.ts index cc05ce94..e0d0db32 100644 --- a/apps/36-blocks/src/app/panel/users/management/management.component.ts +++ b/apps/36-blocks/src/app/panel/users/management/management.component.ts @@ -4,9 +4,12 @@ import { Component, OnInit, OnDestroy, + OnChanges, + SimpleChanges, ViewChild, TemplateRef, inject, + Input, } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ReactiveFormsModule } from '@angular/forms'; @@ -83,7 +86,7 @@ interface IRole { styleUrls: ['./management.component.scss'], providers: [FeatureComponentStore, UserComponentStore], }) -export class ManagementComponent implements OnInit, OnDestroy { +export class ManagementComponent implements OnInit, OnDestroy, OnChanges { private featureComponentStore = inject(FeatureComponentStore); private userComponentStore = inject(UserComponentStore); private dialog = inject(MatDialog); @@ -97,6 +100,8 @@ export class ManagementComponent implements OnInit, OnDestroy { itemsPerPage: 1000, pageNo: 1, }; + /** Current block `reference_id` when embedded (e.g. feature edit). Not the feature type id. */ + @Input() referenceId: string | null = null; public roleSearchTerm: string = ''; public permissionSearchTerm: string = ''; public rolesPageSize: number = 25; @@ -214,11 +219,22 @@ export class ManagementComponent implements OnInit, OnDestroy { }); } + ngOnChanges(changes: SimpleChanges): void { + if (changes['referenceId'] && this.referenceId && changes['referenceId'].firstChange === false) { + this.roleForm.patchValue({ feature_id: this.referenceId }, { emitEvent: true }); + this.cdr.markForCheck(); + } + } + ngOnInit(): void { this.featureComponentStore.getFeature({ ...this.params }); - this.features$.subscribe((features) => { + this.features$.pipe(takeUntil(this.destroy$)).subscribe((features) => { if (features) { this.filterFeatures(features.data); + const referenceId = this.roleForm.get('feature_id')?.value as string | null; + if (referenceId) { + this.bindSelectedFeatureByReferenceId(referenceId); + } this.cdr.markForCheck(); } }); @@ -297,12 +313,7 @@ export class ManagementComponent implements OnInit, OnDestroy { // Subscribe to feature selection changes this.roleForm.get('feature_id')?.valueChanges.subscribe((referenceId: string | null) => { if (referenceId) { - // Find the selected feature and set its id - const selectedFeature = this.features.find((f) => f.reference_id === referenceId); - if (selectedFeature) { - this.roleForm.get('id')?.setValue(selectedFeature.id, { emitEvent: false }); - this.userComponentStore.getFeatureDetails(of(selectedFeature.id)); - } + this.bindSelectedFeatureByReferenceId(referenceId); // Reset search terms and page indices when feature changes this.roleSearchTerm = ''; this.permissionSearchTerm = ''; @@ -319,6 +330,9 @@ export class ManagementComponent implements OnInit, OnDestroy { this.permissionsPageIndex = 0; } }); + if (this.referenceId) { + this.roleForm.patchValue({ feature_id: this.referenceId }, { emitEvent: true }); + } this.createRole$ .pipe( filter((createRole) => !!createRole), @@ -410,6 +424,18 @@ export class ManagementComponent implements OnInit, OnDestroy { this.features = features.filter((feature) => feature.feature_id === 1); } + /** Loads full feature details for Settings / default roles save. Call after `features` is populated (embed flow can set `feature_id` before the list arrives). */ + private bindSelectedFeatureByReferenceId(referenceId: string): void { + const selectedFeature = this.features.find((f) => f.reference_id === referenceId); + if (!selectedFeature) { + return; + } + this.roleForm.get('id')?.setValue(selectedFeature.id, { emitEvent: false }); + if (!this.featureDetails || this.featureDetails.id !== selectedFeature.id) { + this.userComponentStore.getFeatureDetails(of(selectedFeature.id)); + } + } + public editRole(role: IRole): void { this.isEditMode = true; this.editingRole = role; @@ -635,29 +661,30 @@ export class ManagementComponent implements OnInit, OnDestroy { } } public saveDefaultRoles(): void { - if (this.defaultRolesForm.valid) { - const formData = this.defaultRolesForm.value; - const hiddenRoles: string[] = formData.hiddenDefaultRoles || []; - - const payload: any = { - id: this.featureDetails.id, - body: { - extra_configurations: { - c_roles: { - default_creator_role: formData.defaultRoleForCreator, - default_member_role: formData.defaultRoleForMember, - hide_default_creator_role: hiddenRoles.includes('owner'), - hide_default_member_role: hiddenRoles.includes('user'), - }, - default_role: { - name: 'Owner', - value: 1, - }, + if (!this.defaultRolesForm.valid || !this.featureDetails?.id) { + return; + } + const formData = this.defaultRolesForm.value; + const hiddenRoles: string[] = formData.hiddenDefaultRoles || []; + + const payload: any = { + id: this.featureDetails.id, + body: { + extra_configurations: { + c_roles: { + default_creator_role: formData.defaultRoleForCreator, + default_member_role: formData.defaultRoleForMember, + hide_default_creator_role: hiddenRoles.includes('owner'), + hide_default_member_role: hiddenRoles.includes('user'), + }, + default_role: { + name: 'Owner', + value: 1, }, }, - }; - this.userComponentStore.updateFeature(of(payload)); - } + }, + }; + this.userComponentStore.updateFeature(of(payload)); } public cancelDefaultRoles(): void {