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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ jobs:
- name: Install Dependencies
run: yarn install --frozen-lockfile
- name: Run Prettier through format
run: yarn format-check
run: yarn format:check
1 change: 0 additions & 1 deletion .prettierignore

This file was deleted.

91 changes: 25 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Welcome to `react-native-template` 👋, the go-to template for building mobile
- [Nativewind Integration](#3-nativewind-integration)
- [Full Localization Support](#4-full-localization-support)
- [Typed Expo Router Setup](#5-typed-expo-router-setup)
- [Zodius API Client Setup](#6-zodius-api-client-setup)
- [Orval API Client Setup](#6-orval-api-client-setup)
- [Custom Utility Hooks](#7-custom-utility-hooks)
- [Zustand State Management](#8-zustand-state-management)
- [CI/CD Workflow Configuration](#9-cicd-workflow-configuration)
Expand All @@ -30,7 +30,6 @@ Welcome to `react-native-template` 👋, the go-to template for building mobile
- [Loading](#loading)
- [FormTextInput](#formtextinput)
- [ValidationError](#validationerror)
- [Toaster](#toaster)
7. [Using the Template Effectively](#using-the-template-effectively)
- [Recommended Folder Structure](#recommended-folder-structure)
- [Development Decision Flow Chart](#development-decision-flow-chart)
Expand Down Expand Up @@ -186,30 +185,39 @@ export default Routes;
// router.push(Routes.artists.artist('1').songs.song('2'));
```

<a name="6-zodius-api-client-setup"></a>
<a name="6-orval-api-client-setup"></a>

### 6. Zodius API Client Setup 📡
### 6. Orval API Client Setup 📡

A pre-configured Zodius API client with Tenstack Query for managing API calls. The `./api` folder includes a fully set up example for GET and POST requests, complete with schemas, definitions, and global error handling through a custom Zodius plugin.
A pre-configured Orval setup generates a typed API client and TanStack Query hooks from your OpenAPI spec. The `api/generated` folder contains endpoints, models, and optional MSW mocks, powered by a custom Axios mutator and React Query.

```bash
# Generate the client from your OpenAPI schema
yarn gen-api
```

```typescript
import { Zodios } from '@zodios/core';
import { ZodiosHooks } from '@zodios/react';
import apiErrorPlugin from './api-error-plugin';
import exampleApi from './example';
// Use generated React Query hooks
import { useGetRandomFact, useGetFacts } from 'api/generated/endpoints';

const API_URL = process.env.EXPO_PUBLIC_API_URL || '';
const { data, isLoading, error } = useGetRandomFact({ max_length: 140 });
```

// Zodios API client
const apiClient = new Zodios(API_URL, [...exampleApi]);
```typescript
// Imperative request (without a hook)
import { getRandomFact } from 'api/generated/endpoints';

// Apply global error handling
apiClient.use(apiErrorPlugin);
const { data } = await getRandomFact({ max_length: 140 });
```

// Zodios hooks for react
const api = new ZodiosHooks('exampleApi', apiClient);
```typescript
// Global headers and base URL are configured via Axios
// Base URL: env.EXPO_PUBLIC_API_URL (see api/axios-instance.ts)
// Headers: injected by ApiProvider (see utils/providers/api-provider.ts)
import { ApiProvider } from '@utils/providers/api-provider';

export { api, apiClient };
// Wrap your app (e.g., in your root layout)
<ApiProvider>{children}</ApiProvider>;
```

<a name="7-custom-utility-hooks"></a>
Expand Down Expand Up @@ -623,55 +631,6 @@ import { WithValidationError } from '@components/ValidationError';

The `ValidationError` and `WithValidationError` components help maintain a clean UI by only showing error messages when necessary, enhancing the user experience with clear feedback.

<a name="toaster"></a>

## Toaster 🍞

The `Toaster` component is a dynamic and interactive toast notification system designed to provide immediate feedback to users. It's connected to a store for global state management and comes with an API plugin for automatic display on API events.

### Component Features

- **Gesture Support**: Users can dismiss the toast by dragging it down, thanks to the integrated gesture handler.
- **Animated Visibility**: Uses `react-native-reanimated` for smooth show and hide animations.
- **Safe Area Handling**: Accounts for device safe areas, ensuring the toast is always visible and accessible.
- **Custom Icons**: Displays icons for error, success, or information based on the toast type.

### How It Works

The `Toaster` component listens to the toast state from `useToastStore`. When a toast is set, it animates into view. It can be dismissed with a drag gesture or by pressing the 'Dismiss' button.

### Usage

The `Toaster` component does not need to be manually managed; it works by setting the toast state through the `useToastStore` actions:

```javascript
useToastStore.getState().setToast({
type: 'success',
message: 'Your changes have been saved!',
});
```

### Customizing the Toaster

While the `Toaster` itself does not require props, you can customize the animations and styles directly within the component's file if needed.

### API Integration

`apiToastPlugin` is set up to automatically display toasts in response to API calls, making use of the `ZodiosPlugin` system. It provides feedback for errors and successes, skipping certain URLs or GET requests as configured.

### Example of Plugin Usage

Simply add the `apiToastPlugin` to your Zodios API client configuration:

```javascript
const apiClient = new Zodios(API_URL, [
/* ...endpoints */
]);
apiClient.use(apiToastPlugin);
```

The `Toaster` provides a smooth, user-friendly notification mechanism that enhances the interactivity of the application, keeping users informed with minimal disruption.

## More Components Comming Soon... 🎉

Stay tuned for more components and features that will be added to the template in the future. We're committed to providing a comprehensive set of tools and solutions to help you build your mobile applications with ease.
Expand Down
22 changes: 0 additions & 22 deletions api/api-error-plugin.ts

This file was deleted.

66 changes: 0 additions & 66 deletions api/api-toast-plugin.ts

This file was deleted.

27 changes: 0 additions & 27 deletions api/api-token-plugin.ts

This file was deleted.

14 changes: 0 additions & 14 deletions api/api.ts

This file was deleted.

35 changes: 35 additions & 0 deletions api/axios-instance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Axios, {
type AxiosError,
type AxiosRequestConfig,
type AxiosResponse,
} from 'axios';
import env from '../env';

export const AXIOS_INSTANCE = Axios.create({
baseURL: env.EXPO_PUBLIC_API_URL,
});

// add a second `options` argument here if you want to pass extra options to each generated query
export const customAxios = <T>(
config: AxiosRequestConfig,
options?: AxiosRequestConfig,
): Promise<AxiosResponse<T, unknown>> => {
const source = Axios.CancelToken.source();
const promise = AXIOS_INSTANCE({
...config,
...options,
cancelToken: source.token,
}).then((data) => data);

// @ts-expect-error: The cancel method is not typed.
promise.cancel = () => {
source.cancel('Query was cancelled');
};

return promise;
};

// In some case with react-query and swr you want to be able to override the return error type so you can also do it here like this
export type ErrorType<Error> = AxiosError<Error>;

export type BodyType<BodyData> = BodyData;
47 changes: 0 additions & 47 deletions api/example/index.ts

This file was deleted.

Loading