Skip to content

Commit

Permalink
move the sample app to apps subfolder (#187)
Browse files Browse the repository at this point in the history
  • Loading branch information
alan2207 committed Jul 20, 2024
1 parent 7ca3bb8 commit 1508d6d
Show file tree
Hide file tree
Showing 175 changed files with 85 additions and 70 deletions.
16 changes: 11 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
name: CI
on:
push:
branches: ['*']
branches: ["*"]
paths-ignore:
- 'README.md'
- 'docs/**'
- "README.md"
- "docs/**"
pull_request:
branches: [master]
paths-ignore:
- 'README.md'
- 'docs/**'
- "README.md"
- "docs/**"
jobs:
all-cli-check:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./apps/react-vite
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
Expand All @@ -33,6 +36,9 @@ jobs:
e2e:
timeout-minutes: 60
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./apps/react-vite
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
Expand Down
35 changes: 1 addition & 34 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,40 +1,7 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/e2e/.auth/

# storybook
migration-storybook.log
storybook.log
storybook-static


# production
/dist

# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*


# local
mocked-db.json

.DS_Store
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
yarn lint-staged
yarn --cwd apps/react-vite lint-staged
File renamed without changes.
File renamed without changes.
File renamed without changes.
40 changes: 40 additions & 0 deletions apps/react-vite/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/e2e/.auth/

# storybook
migration-storybook.log
storybook.log
storybook-static


# production
/dist

# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*


# local
mocked-db.json

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ export const create = (<T>(stateCreator: zustand.StateCreator<T>) => {
console.log('zustand create mock');

// to support curried version of create
return typeof stateCreator === 'function' ? createUncurried(stateCreator) : createUncurried;
return typeof stateCreator === 'function'
? createUncurried(stateCreator)
: createUncurried;
}) as typeof zustand.create;

const createStoreUncurried = <T>(stateCreator: zustand.StateCreator<T>) => {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
6 changes: 3 additions & 3 deletions docs/api-layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

When your application interacts with either RESTful or GraphQL APIs, it is beneficial to use a single instance of the API client that has been pre-configured and can be reused throughout the application. For example, you can create a single API client instance using the native fetch API or libraries such as [axios](https://github.com/axios/axios), [graphql-request](https://github.com/prisma-labs/graphql-request), or [apollo-client](https://www.apollographql.com/docs/react/) with predefined configuration settings.

[API Client Example Code](../src/lib/api-client.ts)
[API Client Example Code](../apps/react-vite/src/lib/api-client.ts)

### Define and Export Request Declarations

Expand All @@ -19,5 +19,5 @@ Every API request declaration should consist of:

This approach simplifies the tracking of defined endpoints available in the application. Additionally, typing the responses and inferring them further down the application enhances application type safety.

[API Request Declarations - Query - Example Code](../src/features/discussions/api/get-discussions.ts)
[API Request Declarations - Mutation - Example Code](../src/features/discussions/api/create-discussion.ts)
[API Request Declarations - Query - Example Code](../apps/react-vite/src/features/discussions/api/get-discussions.ts)
[API Request Declarations - Mutation - Example Code](../apps/react-vite/src/features/discussions/api/create-discussion.ts)
8 changes: 4 additions & 4 deletions docs/components-and-styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,17 @@ Keep your code style consistent. For example, if you name your components using

If your component is accepting too many props you might consider splitting it into multiple components or use the composition technique via children or slots.

[Composition Example Code](../src/components/ui/dialog/confirmation-dialog/confirmation-dialog.tsx)
[Composition Example Code](../apps/react-vite/src/components/ui/dialog/confirmation-dialog/confirmation-dialog.tsx)

#### Abstract shared components into a component library

For larger projects, it is a good idea to build abstractions around all the shared components. It makes the application more consistent and easier to maintain. Identify repetitions before creating the components to avoid wrong abstractions.

[Component Library Example Code](../src/components/ui/button/button.tsx)
[Component Library Example Code](../apps/react-vite/src/components/ui/button/button.tsx)

It is a good idea to wrap 3rd party components as well in order to adapt them to the application's needs. It might be easier to make the underlying changes in the future without affecting the application's functionality.

[3rd Party Component Example Code](../src/components/ui/link/link.tsx)
[3rd Party Component Example Code](../apps/react-vite/src/components/ui/link/link.tsx)

## Component libraries

Expand Down Expand Up @@ -101,4 +101,4 @@ With the rise of headless component libraries, there is another tier of componen

[Storybook](https://storybook.js.org/) is a great tool for developing and testing components in isolation. Think of it as a catalogue of all the components your application is using. Very useful for developing and discoverability of components.

[Storybook Story Example Code](../src/components/ui/button/button.stories.tsx)
[Storybook Story Example Code](../apps/react-vite/src/components/ui/button/button.stories.tsx)
4 changes: 2 additions & 2 deletions docs/error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

Implement an interceptor to manage errors effectively. This interceptor can be utilized to trigger notification toasts informing users of errors, log out unauthorized users, or send requests to refresh tokens to maintain secure and seamless application operation.

[API Errors Notification Example Code](../src/lib/api-client.ts)
[API Errors Notification Example Code](../apps/react-vite/src/lib/api-client.ts)

### In App Errors

Utilize error boundaries in React to handle errors within specific parts of your application. Instead of having only one error boundary for the entire app, consider placing multiple error boundaries in different areas. This way, if an error occurs, it can be contained and managed locally without disrupting the entire application's functionality, ensuring a smoother user experience.

[Error Boundary Example Code](../src/app/routes/app/discussions/discussion.tsx)
[Error Boundary Example Code](../apps/react-vite/src/app/routes/app/discussions/discussion.tsx)

### Error Tracking

Expand Down
2 changes: 1 addition & 1 deletion docs/performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Code splitting involves splitting production JavaScript into smaller files to op

Ideally, code splitting should be implemented at the routes level, ensuring that only essential code is loaded initially, with additional parts fetched lazily as needed. It's important to avoid excessive code splitting, as this can lead to a performance decline due to the increased number of requests required to fetch all the code chunks. Strategic code splitting, focusing on critical parts of the application, helps balance performance optimization with efficient resource loading.

[Code Splitting Example Code](../src/app/routes/index.tsx)
[Code Splitting Example Code](../apps/react-vite/src/app/routes/index.tsx)

### Component and state optimizations

Expand Down
4 changes: 2 additions & 2 deletions docs/project-standards.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ Enforcing project standards is crucial for maintaining code quality, consistency

ESLint serves as a valuable linting tool for JavaScript, helping developers in maintaining code quality and adhering to coding standards. By configuring rules in the `.eslintrc.js` file, ESLint helps identify and prevent common errors, ensuring code correctness and promoting consistency throughout the codebase. This approach not only helps in catching mistakes early but also enforces uniformity in coding practices, thereby enhancing the overall quality and readability of the code.

[ESLint Configuration Example Code](../.eslintrc.cjs)
[ESLint Configuration Example Code](../apps/react-vite/.eslintrc.cjs)

#### Prettier

Prettier is a useful tool for maintaining consistent code formatting in your project. By enabling the "format on save" feature in your IDE, code is automatically formatted according to the rules set in the `.prettierrc` configuration file. This practice ensures a uniform code style across your codebase and provides helpful feedback on code issues. If the auto-formatting fails, it signals potential syntax error. Furthermore, Prettier can be integrated with ESLint to handle code formatting tasks alongside enforcing coding standards effectively throughout the development process.

[Prettier Configuration Example Code](../.prettierrc)
[Prettier Configuration Example Code](../apps/react-vite/.prettierrc)

#### TypeScript

Expand Down
10 changes: 5 additions & 5 deletions docs/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Opting to store tokens in cookies, configured with the `HttpOnly` attribute, can

In addition to securely storing tokens, it's crucial to protect the entire application from Cross-Site Scripting (XSS) attacks. One key strategy is to sanitize all user inputs before displaying them in the application. By carefully sanitizing inputs, you can reduce the risk of XSS vulnerabilities, making the application more resilient to malicious attacks and enhancing overall security for users.

[HTML Sanitization Example Code](../src/components/ui/md-preview/md-preview.tsx)
[HTML Sanitization Example Code](../apps/react-vite/src/components/ui/md-preview/md-preview.tsx)

For a full list of security risks, check [OWASP](https://owasp.org/www-project-top-10-client-side-security-risks/).

Expand All @@ -33,7 +33,7 @@ If you are already using `react-query`, you can use [react-query-auth](https://g

User information should be treated as a central piece of data accessible throughout the application. If you are already using `react-query`, consider using it for storing user data as well. Alternatively, you can leverage React context with hooks or opt for a third-party state management library to efficiently manage user state across your application.

[Auth Configuration Example Code](../src/lib/auth.tsx)
[Auth Configuration Example Code](../apps/react-vite/src/lib/auth.tsx)

The application will assume the user is authenticated if a user object is present.

Expand All @@ -43,16 +43,16 @@ Authorization is the process of verifying whether a user has permission to acces

#### RBAC (Role based access control)

[Authorization Configuration Example Code](../src/lib/authorization.tsx)
[Authorization Configuration Example Code](../apps/react-vite/src/lib/authorization.tsx)

In a role-based authorization model, access to resources is determined by defining specific roles and associating them with permissions. For example, roles such as `USER` and `ADMIN` can be assigned different levels of access rights within the application. Users are then granted access based on their roles; for instance, restricting certain functionalities to regular users while permitting administrators to access all features and functionalities.

[RBAC Example Code](../src/features/discussions/components/create-discussion.tsx)
[RBAC Example Code](../apps/react-vite/src/features/discussions/components/create-discussion.tsx)

#### PBAC (Permission based access control)

While Role-Based Access Control (RBAC) provides a structured methodology for authorization, there are instances where a more granular approach is necessary. Precision-Based Access Control (PBAC) offers a more flexible solution, particularly in scenarios where access permissions need to be finely tuned based on specific criteria, such as allowing only the owner of a resource to perform certain operations. For example, in the case of a user's comment, PBAC ensures that only the author of the comment has the privilege to delete it, adding a layer of precision and customization to access control mechanisms.

For RBAC protection, you can use the `RBAC` component by passing allowed roles to it. On the other hand, if you need more strict protection, you can pass policies check to it.

[PBAC Example Code](../src/features/comments/components/comments-list.tsx)
[PBAC Example Code](../apps/react-vite/src/features/comments/components/comments-list.tsx)
14 changes: 7 additions & 7 deletions docs/state-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Component state is specific to individual components and should not be shared gl
- [useState](https://react.dev/reference/react/useState) - for simpler states that are independent
- [useReducer](https://react.dev/reference/react/useReducer) - for more complex states where on a single action you want to update several pieces of state

[Component State Example Code](../src/components/layouts/dashboard-layout.tsx)
[Component State Example Code](../apps/react-vite/src/components/layouts/dashboard-layout.tsx)

## Application State

Expand All @@ -24,7 +24,7 @@ Good Application State Solutions:
- [jotai](https://github.com/pmndrs/jotai)
- [xstate](https://xstate.js.org/)

[Global State Example Code](../src/components/ui/notifications/notifications-store.ts)
[Global State Example Code](../apps/react-vite/src/components/ui/notifications/notifications-store.ts)

## Server Cache State

Expand All @@ -38,7 +38,7 @@ Good Server Cache Libraries:
- [urql](https://formidable.com/open-source/urql/) - GraphQl
- [RTK](https://redux-toolkit.js.org/rtk-query)

[Server Cache State Example Code](../src/features/discussions/api/get-discussions.ts)
[Server Cache State Example Code](../apps/react-vite/src/features/discussions/api/get-discussions.ts)

## Form State

Expand All @@ -56,19 +56,19 @@ Although it is possible to build any form using only React primitives, there are

Create abstracted `Form` component and all the input field components that wrap the library functionality and are adapted to the application needs.

[Form Example Code](../src/components/ui/form/form.tsx)
[Form Example Code](../apps/react-vite/src/components/ui/form/form.tsx)

[Input Field Example Code](../src/components/ui/form/input.tsx)
[Input Field Example Code](../apps/react-vite/src/components/ui/form/input.tsx)

You can also integrate validation libraries with the mentioned solutions to validate inputs on the client. Some good options are:

- [zod](https://github.com/colinhacks/zod)
- [yup](https://github.com/jquense/yup)

[Validation Example Code](../src/features/auth/components/register-form.tsx)
[Validation Example Code](../apps/react-vite/src/features/auth/components/register-form.tsx)

## URL State

URL state refers to the data stored and manipulated within the address bar of the browser. This state is commonly managed through URL parameters (e.g., /app/${dynamicParam}) or query parameters (e.g., /app?dynamicParam=1). By incorporating routing solutions like react-router-dom, you can effectively access and control the URL state, enabling dynamic manipulation of application parameters directly from the browser's address bar.

[URL State Example Code](../src/features/discussions/components/discussion-view.tsx)
[URL State Example Code](../apps/react-vite/src/features/discussions/components/discussion-view.tsx)
10 changes: 5 additions & 5 deletions docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ As highlighted in this [tweet](https://twitter.com/rauchg/status/807626710350839

Unit tests are the smallest tests you can write. They test individual parts of your application in isolation. They are useful for testing shared components and functions that are used throughout the entire application. They are also useful for testing complex logic in a single component. They are fast to run and easy to write.

[Unit Test Example Code](../src/components/ui/dialog/confirmation-dialog/__tests__/confirmation-dialog.test.tsx)
[Unit Test Example Code](../apps/react-vite/src/components/ui/dialog/confirmation-dialog/__tests__/confirmation-dialog.test.tsx)

### Integration Tests

Integration testing checks how different parts of your application work together. It's crucial to focus on integration tests for most of your testing, as they provide significant benefits and boost confidence in your application's reliability. While unit tests are helpful for individual parts, passing them doesn't guarantee your app will function correctly if the connections between parts are flawed. Testing various features with integration tests is vital to ensure that your application works smoothly and consistently.

[Integration Test Example Code](../src/app/routes/app/discussions/__tests__/discussion.test.tsx)
[Integration Test Example Code](../apps/react-vite/src/app/routes/app/discussions/__tests__/discussion.test.tsx)

### E2E

End-to-End Testing is a method that evaluates an application as a whole. These tests involve automating the complete application, including both the frontend and backend, to confirm that the entire system functions correctly. End-to-End tests simulate how a user would interact with the application.

[E2E Example Code](../e2e/tests/smoke.spec.ts)
[E2E Example Code](../apps/react-vite/e2e/tests/smoke.spec.ts)

## Recommended Tooling:

Expand All @@ -46,8 +46,8 @@ For prototyping the API use msw, which is a great tool for quickly creating fron

It can be used for designing API endpoints. The business logic of the mocked API can be created in its handlers.

[API Handlers Example Code](../src/testing/mocks/handlers/auth.ts)
[API Handlers Example Code](../apps/react-vite/src/testing/mocks/handlers/auth.ts)

[Data Models Example Code](../src/testing/mocks/db.ts)
[Data Models Example Code](../apps/react-vite/src/testing/mocks/db.ts)

Having a fully functional mocked API server is also handy when it comes to testing, you don't have to mock fetch, but make requests to the mocked server instead with the data your application would expect.

0 comments on commit 1508d6d

Please sign in to comment.