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
95 changes: 33 additions & 62 deletions .github/instructions/ui/components.instructions.md
Original file line number Diff line number Diff line change
@@ -1,82 +1,53 @@
---
applyTo: "apps/ui-sharethrift/src/components/**/*"
---
# Copilot Instructions: UI Components

## Purpose

- The `components` directory provides reusable UI building blocks for the applicant-facing web UI.
- Components are built with React, TypeScript, and leverage Ant Design and Tailwind CSS for styling.

## Architecture & Patterns

- **React + TypeScript**: Component-driven UI with strict typing for reliability and maintainability.
- **Ant Design & Tailwind CSS**: Use Ant Design components and theming wherever possible; use Tailwind CSS for custom styles.
- **Feature-based Structure**: Organize components and logic by feature or domain concept.
- **State Management**: Use React hooks and context for local and global state. Avoid prop drilling and trivial state management solutions.
- **Accessibility**: Ensure all components are accessible (ARIA, keyboard navigation, semantic HTML).

## Coding Conventions

- Use functional components and React hooks.
- Prefer composition over inheritance.
- Use strict TypeScript types for props, state, and context.
- Component name must match file name in PascalCase. Each component file should export a single component.
- Each component must have a corresponding `{ComponentName}Props` type defined.
- Use kebab-case for file and directory names.
- Use the [Container pattern](https://www.patterns.dev/react/presentational-container-pattern/) for separating concerns for data fetching/manipulation and presentation.
- Suffix container components with `Container` (e.g., `ProfileViewContainer`).

## Styling
## Overview

- Use Ant Design components and theming for UI consistency.
- Use Tailwind CSS for custom component styles.
- Prefer CSS modules or scoped styles for custom styles if Tailwind is not suitable.
This directory contains reusable UI components for the applicant-facing web UI, built with **React**, **TypeScript**, **Ant Design**, and **Tailwind CSS**.

## State Management
## Principles

- Use React hooks (`useState`, `useEffect`, etc.) for local state.
- Use context or state management libraries only when necessary for shared/global state.
- **Component-driven & Typed**: Use functional React components with strict TypeScript typing.
- **Styling**: Prefer Ant Design components and theming; use Tailwind CSS or CSS Modules for custom styles.
- **Accessibility**: Ensure ARIA support, keyboard navigation, and semantic HTML.
- **Testing**: Every component must include a unit test and a Storybook story.

## Accessibility
## Structure & Naming

- Prefer components to be accessible (ARIA attributes, keyboard navigation, semantic HTML) where possible.
- Use accessible Ant Design components.
- Use the [Container Pattern](https://www.patterns.dev/react/presentational-container-pattern/):
- Suffix container components with `Container` (e.g., `ProfileViewContainer`).
- Component file must:
- Export a single PascalCase-named component.
- Include a `{ComponentName}Props` type.
- Use kebab-case for file and folder names.

## Testing
## State & Logic

- Write unit tests for components, especially for logic and rendering.
- Every component must have a corresponding Storybook story.
- Use `useState`, `useEffect`, and other React hooks for local state.
- Use React Context or state libraries only when shared/global state is needed.
- Avoid prop drilling and trivial state solutions.

## Error Handling
## Code Conventions

- Handle loading states gracefully. (e.g `<Skeleton />`)
- Propagate error messages via Ant Design components (e.g. `message`)
- Use fallback UI for no data (e.g., `<Empty />`)

## Reusability

- Make components reusable and composable.
- Avoid hardcoding values; use props and context.

## Naming Conventions

- Use PascalCase for component names.
- Suffix container components with `Container` (e.g., `ProfileViewContainer`).
- Prefer composition over inheritance.
- Memoize expensive computations (`useMemo`, `React.memo`).
- Avoid unnecessary re-renders.
- Make components composable and reusable—avoid hardcoded values.

## Performance
## UX & Error Handling

- Memoize expensive computations with `useMemo` or `React.memo`.
- Avoid unnecessary re-renders.
- Handle loading (`<Skeleton />`), empty states (`<Empty />`), and errors (`message`) gracefully.

## File Organization
## Organization

- Place shared components in the `shared/` folder.
- Place layout-specific components in the appropriate `layouts/` folder.
- Use `shared/` for common components.
- Use `layouts/` for layout-specific components.

## References

- [React Documentation](https://react.dev/)
- [Ant Design Documentation](https://ant.design/docs/react/introduce)
- [Storybook Documentation](https://storybook.js.org/docs/react/get-started/introduction)
- [TypeScript Handbook](https://www.typescriptlang.org/docs/)
- [React](https://react.dev/)
- [Ant Design](https://ant.design/docs/react/introduce)
- [Tailwind CSS](https://tailwindcss.com/docs)
- [Storybook](https://storybook.js.org/docs/react/get-started/introduction)
- [TypeScript](https://www.typescriptlang.org/docs/)
59 changes: 24 additions & 35 deletions .github/instructions/ui/container-components.instructions.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,43 @@
---
applyTo: "apps/ui-sharethrift/src/components/**/*.container.tsx"
---
# Copilot Instructions: Container Components

## Purpose

- Container components manage data fetching, business logic, and state for their corresponding presentational components.
- They separate concerns by isolating side effects, API calls, and state management from UI rendering.

## Architecture & Patterns
## Overview

- **Container/Presentational Pattern**: Each container component (`*.container.tsx`) wraps a presentational component, passing props derived from state, context, or API responses.
- **Co-location**: Place container components next to their presentational counterparts and related `.graphql` files for maintainability.
- **GraphQL Integration**: Use Apollo Client hooks (`useQuery`, `useMutation`, etc.) for data operations. Import queries/mutations from adjacent `.graphql` files.
Container components handle **data fetching**, **state**, and **business logic**, separating concerns from UI rendering. They wrap and supply props to corresponding presentational components.

## Coding Conventions
## Principles

- Use functional components and React hooks.
- Suffix container components with `Container` (e.g., `ProfileViewContainer`).
- Component name must match file name in PascalCase.
- Each container must define a `{ComponentName}ContainerProps` type for its props.
- Use strict TypeScript types for all state, props, and API responses.
- Use kebab-case for file and directory names.
- Provide handler functions through display component props for all relevant actions (e.g., handleClick, handleChange, handleSubmit, handleSave).
- **Container/Presentational Pattern**: Container components (`*.container.tsx`) derive props from state, context, or API, and pass them to presentational components.
- **Colocation**: Place containers next to their UI counterparts and related `.graphql` files for clarity and maintainability.

## State Management
## Data & State

- Use React hooks (`useState`, `useEffect`, `useContext`) for local and shared state only when necessary. Avoid prop drilling and trivial state management solutions.
- Use **Apollo Client** hooks (`useQuery`, `useMutation`, etc.) for GraphQL operations.
- Use **React hooks** (`useState`, `useEffect`, `useContext`) for local and shared state when necessary.
- Use `ComponentQueryLoader` for standardized loading, error, and empty states.

## Data Fetching
## Code Conventions

- Use Apollo Client hooks for GraphQL queries and mutations.
- Leverage the shared `ComponentQueryLoader` component for consistent data fetching, loading, and error handling.
- Use functional components and strict TypeScript typing (`{ComponentName}ContainerProps`).
- Match file name and component name (PascalCase).
- Use `Container` suffix (e.g., `ProfileViewContainer`).
- Follow kebab-case for file and directory names.
- Provide handler props for actions (e.g., `handleClick`, `handleSubmit`).

## Error Handling

- Use the `ComponentQueryLoader` for consistent error handling and fallback UI via the optional `errorComponent` or `noDataComponent` props

## Accessibility

- Ensure all rendered UI is accessible, including loading and error states.

- Use `ComponentQueryLoader` with `errorComponent` and `noDataComponent` props for graceful fallbacks.
- Ensure accessibility for loading/error states.

## File Organization
## File Structure

- Place container components in the same folder as their presentational components and related `.graphql` files.
- Align container and presentational components by keeping their file names consistent (e.g., `profile-view.container.tsx` and `profile-view.tsx`).
- Co-locate:
- Container and presentational components (e.g., `profile-view.container.tsx` + `profile-view.tsx`)
- Related `.graphql` files in the same directory.

## References

- [React Container/Presentational Pattern](https://www.patterns.dev/react/presentational-container-pattern/)
- [Apollo Client Docs](https://www.apollographql.com/docs/react/)
- [Ant Design Documentation](https://ant.design/docs/react/introduce)
- [Container/Presentational Pattern](https://www.patterns.dev/react/presentational-container-pattern/)
- [Apollo Client](https://www.apollographql.com/docs/react/)
- [Ant Design](https://ant.design/docs/react/introduce)
183 changes: 91 additions & 92 deletions .github/instructions/ui/graphql.instructions.md
Original file line number Diff line number Diff line change
@@ -1,94 +1,93 @@
---
applyTo: "apps/ui-sharethrift/src/components/**/*.graphql"
---

## Copilot Instructions: GraphQL

### Purpose

- `.graphql` files in the frontend define GraphQL queries, mutations, and fragments for use with Apollo Client and React components.
- They enable type-safe, modular, and maintainable data fetching and manipulation.

### Organization & Structure

- Place `.graphql` files next to the component or container that uses them, typically in the same feature or layout folder.
- For a given container component, there should be a corresponding `.graphql` file with the same base name. (e.g `contact-details.container.graphql`)
- All queries, mutations, and fragments used in the container component should be defined in the corresponding `.graphql` file.

### Coding Conventions

- Queries and mutations should use the following naming convention `<Layout><Container><Operation>`
- Given a container component named `ContactDetailsContainer` in the `applicant` layout which uses the `ApplicantUser` query, the query name should be: `ApplicantContactDetailsContainerApplicantUser`
- Fragments should use the following naming convention `<Layout><Container><Type>Fields`
- Given a container component named `ContactDetailsContainer` in the `applicant` layout, a fragment for the `ApplicantUser` type should be named: `ApplicantContactDetailsContainerUserFields`
- Always prefer reusable fragments over direct field access in queries/mutations.
- Use variables for dynamic values; avoid hardcoding IDs or parameters.
- Keep queries minimal—request only the fields needed by the component.
- Include the `id` fields on fragment types where the `id` field is present to ensure consistency in Apollo Cache.
- Ensure queries and mutations use the same fragment definitions to ensure consistency in Apollo Cache.

### Integration


- Import `.graphql` files into TypeScript/JS files using codegen-generated types for type safety.
- Use Apollo Client hooks (`useQuery`, `useMutation`, etc.) with imported queries/mutations.
- Co-locate fragments with the components that use them for maintainability.

### Apollo Client Link Chain Customization

- Configure Apollo Client with a dynamic link chain to flexibly route operations to different data sources:
- **Batching**: Use a batching link (e.g., `BatchHttpLink`) to combine multiple GraphQL operations into a single HTTP request. This is why container components are allowed to define their own queries and mutations; the batching link can optimize their execution on the server.
- **Authentication & Custom Headers**: Add custom Apollo links to inject authentication tokens or other headers into requests.
- **REST Integration**: Use Apollo's REST link to fetch data from non-GraphQL APIs. Route specific operations to REST endpoints using a link map and split logic. Typical usage is for fetching JSON data from Azure Blob Storage.
- Example generalized setup:
```ts
import { ApolloClient, InMemoryCache, ApolloLink, from } from '@apollo/client';
import { BatchHttpLink } from '@apollo/client/link/batch-http';
import { RestLink } from 'apollo-link-rest';

// Define links for different data sources
const batchGraphqlLink = new BatchHttpLink({ uri: '/graphql', batchMax: 10, batchInterval: 20 });
const restApiLink = new RestLink({ uri: '/rest-api' });

// Custom links for authentication, headers, etc.
const authLink = new ApolloLink((operation, forward) => {
operation.setContext(({ headers = {} }) => ({
headers: {
...headers,
Authorization: 'Bearer <token>'
}
}));
return forward(operation);
});

// Link map for routing operations
const linkMap = {
CountryDetails: restApiLink, // Example: route 'CountryDetails' query to REST
default: from([authLink, batchGraphqlLink])
};

// Dynamic split logic based on operation name
const dynamicLink = ApolloLink.split(
operation => operation.operationName in linkMap,
new ApolloLink((operation, forward) => {
const link = linkMap[operation.operationName as keyof typeof linkMap] || linkMap.default;
return link.request(operation, forward);
}),
linkMap.default
);

const client = new ApolloClient({
cache: new InMemoryCache(),
link: dynamicLink
});
```
- You can extend this pattern to route based on context, operation type, or other criteria. Update the link chain dynamically (e.g., on authentication changes) as needed.

### Testing

- Mock queries and mutations in Storybook stories and unit tests using Apollo Client's mocking utilities.

### Example Structure
# Copilot Instructions: GraphQL Files

`.graphql` files define queries, mutations, and fragments used with **Apollo Client** in React components. They support **type-safe**, **modular**, and **maintainable** data access.

## Organization

- Co-locate `.graphql` files with related container and presentational components.
- Use consistent base filenames (e.g., `contact-details.container.graphql` for `contact-details.container.tsx`).
- Define all GraphQL operations used by a container in its corresponding `.graphql` file.

## Naming Conventions

- **Queries & Mutations**:
Format: `<Layout><Container><Operation>`
Example: `ApplicantContactDetailsContainerApplicantUser`

- **Fragments**:
Format: `<Layout><Container><Type>Fields`
Example: `ApplicantContactDetailsContainerUserFields`

## Coding Guidelines

- Use Apollo variables—avoid hardcoded IDs or params.
- Keep queries minimal; only fetch fields needed by the component.
- Prefer reusable **fragments** over inline fields.
- Always include `id` in fragments where applicable to support Apollo cache normalization.
- Reuse consistent fragments across queries and mutations for cache alignment.

## Integration

- Import `.graphql` files using codegen-generated types.
- Use Apollo hooks (`useQuery`, `useMutation`) in container components.
- Co-locate fragments with the components that consume them.

## Apollo Link Chain

Apollo Client is configured with a **custom link chain** to flexibly route GraphQL and REST operations:

- **Batching**: Use `BatchHttpLink` to group GraphQL operations into a single request.
- **Auth & Headers**: Use `ApolloLink` to inject headers and tokens.
- **REST Support**: Use `RestLink` for non-GraphQL APIs (e.g., Azure Blob Storage).
- **Dynamic Routing**: Route operations using a `linkMap` and `ApolloLink.split`.

### Example Link Chain Setup

```ts
import { ApolloClient, InMemoryCache, ApolloLink, from } from '@apollo/client';
import { BatchHttpLink } from '@apollo/client/link/batch-http';
import { RestLink } from 'apollo-link-rest';

const batchGraphqlLink = new BatchHttpLink({ uri: '/graphql', batchMax: 10, batchInterval: 20 });
const restApiLink = new RestLink({ uri: '/rest-api' });

const authLink = new ApolloLink((operation, forward) => {
operation.setContext(({ headers = {} }) => ({
headers: {
...headers,
Authorization: 'Bearer <token>',
}
}));
return forward(operation);
});

const linkMap = {
CountryDetails: restApiLink,
default: from([authLink, batchGraphqlLink]),
};

const dynamicLink = ApolloLink.split(
op => op.operationName in linkMap,
new ApolloLink((op, forward) => {
const link = linkMap[op.operationName] || linkMap.default;
return link.request(op, forward);
}),
linkMap.default
);

const client = new ApolloClient({
cache: new InMemoryCache(),
link: dynamicLink,
});
```

> You can extend this pattern to route based on context, auth state, or operation type.

## Testing

- Use Apollo mocking utilities to simulate queries/mutations in unit tests and Storybook stories.

## Example Structure

```
components/
Expand All @@ -99,7 +98,7 @@ components/
my-component.tsx
```

### References
## References

- [Apollo Client Docs](https://www.apollographql.com/docs/react/)
- [GraphQL Specification](https://spec.graphql.org/)
Loading