> ## Documentation Index
> Fetch the complete documentation index at: https://docs.frankieone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Angular

> This guide walks you through integrating OneSDK with a new Angular project, providing a robust foundation for building KYC/AML features in your Angular application.

## Quick Setup

<Steps>
  <Step title="Install Angular CLI">
    ```shell theme={null}
    npm install -g @angular/cli
    ```
  </Step>

  <Step title="Create New Angular Project">
    ```shell theme={null}
    ng new <project-name>
    ```
  </Step>

  <Step title="Install OneSDK Package">
    ```shell theme={null}
    npm install @frankieone/one-sdk
    ```
  </Step>
</Steps>

## Webpack Configuration

<Accordion title="Setting up Webpack (Optional)">
  <Steps>
    <Step title="Install Dependencies">
      ```shell theme={null}
      npm install -D @angular-builders/custom-webpack file-loader style-loader css-loader @types/react
      ```
    </Step>

    <Step title="Update angular.json">
      Add custom Webpack configuration:

      ```json theme={null}
      {
        "projects": {
          "<project-name>": {
            "architect": {
              "build": {
                "builder": "@angular-builders/custom-webpack:browser",
                "options": {
                  "customWebpackConfig": {
                    "path": "./webpack.config.js"
                  }
                }
              },
              "serve": {
                "builder": "@angular-builders/custom-webpack:dev-server"
              }
            }
          }
        }
      }
      ```
    </Step>

    <Step title="Create webpack.config.js">
      ```javascript theme={null}
      module.exports = {
        module: {
          rules: [
            {
              test: /\.svg$/,
              use: [
                {
                  loader: "file-loader",
                  options: {
                    name: "assets/[name].[hash:8].[ext]",
                  },
                },
              ],
            },
            {
              test: /\.css$/,
              use: [{ loader: "style-loader" }, { loader: "css-loader" }],
              exclude: /src/,
            },
          ],
        },
      };
      ```
    </Step>
  </Steps>
</Accordion>

## TypeScript Configuration

<Accordion title="Configure TypeScript">
  Update your `tsconfig.json` or `tsconfig.app.json`:

  ```json theme={null}
  {
    "compilerOptions": {
      "allowSyntheticDefaultImports": true,
      "skipLibCheck": true
    }
  }
  ```
</Accordion>

## Implementation

<Tabs>
  <Tab title="Component Setup">
    ```typescript app.component.ts theme={null}
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html'
    })
    export class AppComponent implements OnInit {
      async ngOnInit() {
        await this.initializeOneSDK();
      }

      private async initializeOneSDK() {
        const session = await this.getSessionToken();
        const oneSdk = await this.setupSDK(session);
        await this.configureSDK(oneSdk);
      }

      private async getSessionToken() {
        const config = {
          CUSTOMER_ID: '',
          CUSTOMER_CHILD_ID: '',
          API_KEY: ''
        };

        const response = await fetch(
          "https://backend.latest.frankiefinancial.io/auth/v2/machine-session",
          {
            method: "POST",
            headers: {
              authorization: "machine " + btoa([
                config.CUSTOMER_ID,
                config.CUSTOMER_CHILD_ID,
                config.API_KEY
              ].filter(Boolean).join(":")),
              "Content-Type": "application/json"
            },
            body: JSON.stringify({
              permissions: {
                preset: "one-sdk",
                reference: `demo-${new Date().toISOString()}`
              }
            })
          }
        );

        return response.json();
      }

      private async setupSDK(session: any) {
        return await OneSDK({
          session,
          recipe: {
            form: {
              provider: {
                name: 'react',
                googleApiKey: "YOUR_GOOGLE_API_KEY"
              },
            }
          }
        });
      }

      private async configureSDK(oneSdk: any) {
        // Setup event logging
        oneSdk.on('*', console.log);

        // Initialize individual flow
        const individual = oneSdk.individual();
        await this.setupConsent(individual);

        // Configure IDV flow
        await this.setupIDVFlow(oneSdk);
      }

      private async setupConsent(individual: any) {
        individual.addConsent("general");
        individual.addConsent("docs");
        individual.addConsent("creditheader");
        await individual.submit();
      }

      private async setupIDVFlow(oneSdk: any) {
        const component = oneSdk.component as unknown as (arg0: any, arg1?: any) => any;
        const flow = oneSdk.flow as unknown as (arg0: any) => any;

        const idv = flow("idv");
        const loading1 = component("form", {
          name: "LOADING",
          title: { label: "Loading..." },
          descriptions: [{ label: "" }]
        });

        const loading2 = component("form", {
          name: "LOADING",
          title: { label: "Processing results..." },
          descriptions: [{
            label: "Hold tight, this can take up to 30 seconds. Please don't refresh this page."
          }]
        });

        const review = component("form", {
          name: "REVIEW",
          type: "ocr"
        });

        this.setupIDVEventHandlers(idv, loading1, loading2, review);
        idv.mount("#e2e-idv-container");
      }

      private setupIDVEventHandlers(idv: any, loading1: any, loading2: any, review: any) {
        let before = true;

        idv.on("loading", (display: boolean) => {
          if (display && before) {
            loading1.mount("#e2e-idv-loading1");
          } else if (before) {
            loading1.unmount();
            before = false;
          }
        });

        idv.on("results", async ({ checkStatus }: { checkStatus: boolean }) => {
          if (checkStatus) {
            loading2.unmount();
            review.mount("#e2e-idv-container");
          }
        });

        idv.on("detection_complete", () => {
          loading2.mount("#e2e-idv-loading2");
        });

        // Error handling
        idv.on("error", ({ message, payload }: { message: string, payload: any }) => {
          console.error("IDV Error:", message, payload);
        });
      }
    }
    ```
  </Tab>

  <Tab title="Template Setup">
    ```html app.component.html theme={null}
    <div class="idv-container">
      <div id="e2e-idv-container" class="main-container"></div>
      <div id="e2e-idv-loading1" class="loading-container"></div>
      <div id="e2e-idv-loading2" class="loading-container"></div>
    </div>
    ```

    ```css app.component.css theme={null}
    .idv-container {
      display: flex;
      flex-direction: column;
    }

    .main-container {
      min-width: 100vh;
      height: 85vh;
    }

    .loading-container {
      width: 100%;
      min-height: 200px;
    }
    ```
  </Tab>
</Tabs>

## Running the Application

<Steps>
  <Step title="Start Development Server">
    ```shell theme={null}
    npm run start
    ```
  </Step>

  <Step title="Access Application">
    Open your browser and navigate to `http://localhost:4200`
  </Step>
</Steps>

<Callout icon="bell" color="#FFCA16" iconType="regular">
  ##### Security Note

  Never store API keys or credentials in your frontend code. Use environment
  variables and a secure backend service to handle authentication.
</Callout>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Common Issues">
    * **Webpack Configuration Errors**: Ensure all loaders are properly configured in webpack.config.js
    * **TypeScript Errors**: Verify tsconfig.json settings, especially `allowSyntheticDefaultImports`
    * **Component Mounting Issues**: Check if container IDs match in both component and template files
  </Accordion>

  <Accordion title="Best Practices">
    * Use environment variables for API keys and endpoints
    * Implement proper error handling for API calls
    * Follow Angular's lifecycle hooks for initialization
    * Implement proper cleanup in ngOnDestroy
  </Accordion>
</AccordionGroup>

<Card title="Need Help?" icon="circle-question">
  If you encounter issues, check our [sample code
  repository <Icon icon="arrow-up-right-from-square" size={12} />](https://github.com/frankieone/frontend-onesdk-public-sample-codes)
  or reach out to our support team.
</Card>
