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
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,31 @@ pnpm version-packages
After running that, you might notice version bumps on the package's `version` and an update on the package's `CHANGELOG.md`.

3. By now, we just need to commit & push those files and, after merging the PR, the `packages updates` will be automatically published :)

## Documentation Guide

To ensure that all pages, components, and utilities are thoroughly documented in Storybook, please follow these steps.

### 1. Write Storybook Stories

Each component and page should have a corresponding Storybook story that showcases its various states and usage scenarios:

- **Include All Possible States**: Each story should cover possible states of the component or page, such as default, disabled, loading, or error configurations.
- **Use Mocks for Data**: Use MSW (Mock Service Worker) to mock any necessary API requests, ensuring stories are self-contained and reproducible.
- **Decorators**: Pass any necessary decorators to simulate the environment (e.g., authentication with `withTokenSetup`).
- **Type Safety**: Ensure correct typings for all props and arguments.
- **Conciseness**: Be thorough but concise, focusing on the most relevant states and interactions.

**After creating the story**:
- Add the story name to `storySort` in the `preview.ts` file to ensure it appears in the correct order. If you’re unsure where to add this, please ask a COP member for assistance.

### 2. Add MDX Documentation

In addition to stories, create an MDX file to provide detailed documentation for each page or component:

- **Create an MDX File**: Place the `.mdx` file in the corresponding `__storybook__` folder. The file name should match the component or page name (e.g., `Button.mdx` for the `Button` component).
- **Use Consistent Titles**: Match the title in the MDX file to the Storybook story for consistency:
- **Pages**: `@baseapp-frontend-template / Pages/[PageName]`
- **Components**: `@baseapp-frontend-template / [ComponentSection]/[ComponentCategory]/[ComponentName]`

For detailed documentation templates and examples, refer to our [Tettra page](https://app.tettra.co/teams/TSL/pages/frontend-documentation).
27 changes: 27 additions & 0 deletions packages/components/.storybook/Introduction.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Meta } from '@storybook/addon-docs'

<Meta title="Introduction" />

# BaseApp Packages Storybook

## What is Storybook?

Storybook is an open-source tool for building and documenting UI components and pages in isolation. It allows developers to create, test, and document components without needing to rely on the backend or navigate through the entire application. This approach enhances the speed and reliability of UI development by enabling component-focused workflows.

## Purpose of This Storybook

The Storybook for **BaseApp Components Package** serves as a centralized resource for developers, designers or any interested person to:

- **Explore Components**: View, test, and understand the various UI components and pages available in the project.
- **Document Features**: Provide comprehensive documentation for each component and page, ensuring that their purpose, usage, and customization options are clear to all team members.
- **Facilitate Collaboration**: Storybook enables both developers and non-developers to review and discuss UI elements, fostering better communication across the team.

## How to Use This Storybook

1. **Browse Components and Pages**: Navigate through the sidebar to explore the different components and pages. Each item has a detailed documentation section outlining its purpose, props, and usage examples.
2. **Check Component States**: Each component has multiple stories showcasing its different states, such as default, loading, or error configurations. This provides a comprehensive view of how each component behaves in various scenarios.
3. **View Documentation**: Each component and page includes an MDX documentation file with information on usage, props, and additional notes. This documentation is intended to be a reference for all team members, from developers to designers.

## Contribution and Maintenance

For consistency, please follow the documentation standards when adding new components or updating existing ones. You can refer to our [Tettra page](https://app.tettra.co/teams/TSL/pages/frontend-documentation) for detailed guidelines on writing stories and MDX documentation.
4 changes: 3 additions & 1 deletion packages/components/.storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ function getAbsolutePath(value: string): any {
const config: StorybookConfig = {
stories: [
resolve(__dirname, './*.mdx'),
resolve(__dirname, '../modules/**/__storybook__/stories.@(js|jsx|mjs|ts|tsx)'),
resolve(__dirname, '../modules/**/__storybook__/*.mdx'),
resolve(__dirname, '../../design-system/components/**/__storybook__/*.mdx'),
resolve(__dirname, '../modules/**/__storybook__/stories.@(js|jsx|mjs|ts|tsx)'),
Comment on lines +15 to +17
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

No MDX files found in specified directories.

Please ensure that MDX files exist in the following paths:

  • packages/components/modules/**/__storybook__
  • packages/design-system/components/**/__storybook__
🔗 Analysis chain

LGTM! Proper organization of story paths.

The story paths are well-organized with documentation files (.mdx) preceding the story files, which follows best practices for Storybook configuration.

Let's verify the existence of MDX files in the specified paths:


Shell script corrected to verify MDX file existence:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence of MDX files in the specified paths
# Expected: Should find at least one MDX file in each directory

echo "Checking for MDX files in modules directory..."
fd -e mdx . "packages/components/modules/**/__storybook__"

echo "Checking for MDX files in design-system directory..."
fd -e mdx . "packages/design-system/components/**/__storybook__"

Length of output: 1803


Script:

#!/bin/bash
# Description: Verify the existence of MDX files in the specified paths
# Expected: Should find at least one MDX file in each directory

echo "Checking for MDX files in modules directory..."
fd -e mdx "packages/components/modules/**/__storybook__"

echo "Checking for MDX files in design-system directory..."
fd -e mdx "packages/design-system/components/**/__storybook__"

Length of output: 341

resolve(
__dirname,
'../../design-system/components/**/__storybook__/stories.@(js|jsx|mjs|ts|tsx)',
Expand All @@ -25,6 +26,7 @@ const config: StorybookConfig = {
},
staticDirs: [resolve(__dirname, '../public')],
addons: [
'@storybook/addon-docs',
getAbsolutePath('@storybook/addon-webpack5-compiler-babel'),
getAbsolutePath('@storybook/addon-links'),
getAbsolutePath('@storybook/addon-essentials'),
Expand Down
2 changes: 2 additions & 0 deletions packages/components/.storybook/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const preview: Preview = {
// NOTE: Storybook does not accept importing external variables for storySort,
// so the `designSystemStoriesOrder` and `componentsStoriesOrder` are defined inline.
const designSystemStoriesOrder = [
'Introduction',
'Iconography',
// Avatars
'AvatarWithPlaceholder',
Expand Down Expand Up @@ -62,6 +63,7 @@ const preview: Preview = {
]

const componentsStoriesOrder = [
'Introduction',
'Iconography',
// Avatars
'AvatarWithPlaceholder',
Expand Down
8 changes: 8 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @baseapp-frontend/components

## 0.0.16

### Patch Changes

- Storybook cleanup
- Updated dependencies
- @baseapp-frontend/design-system@0.0.17

## 0.0.15

### Patch Changes
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Meta } from '@storybook/addon-docs'

<Meta title="@baseapp-frontend | components/Shared/ReactionButton" />

# Component Documentation

## ReactionButton

- **Purpose**: The `ReactionButton` component provides an interactive button for users to react to content (e.g., like or dislike) with options to handle success and error responses. The component also displays the current reaction count and supports Relay for efficient data loading.
- **Expected Behavior**: When clicked, the button triggers a reaction action and updates the UI to reflect the new state. If the user has already reacted, it shows a "selected" icon. The component should handle loading states and display the total count of reactions.

## Use Cases

- **Current Usage**: This component is currently used within `CommentReactionButton` for `CommentItem`.
- **Potential Usage**: The `ReactionButton` could also be used for other content types that support reactions, such as posts, images, or articles.

## Props

- **target** (ReactionButton_target$key): The target data for the reaction button. Typically a comment or post, providing data about the current reactions.
- **reactionType** (string): Specifies the type of reaction, such as "LIKE" or "DISLIKE".
- **children** (function): Function to render children components with reaction handlers and data. Expected format:
`(props: { handleReaction: () => void, isLoading: boolean, target: ReactionButton_target$data }) => ReactElement | null`
- **handleError** (function): Callback function to handle errors during the reaction process.
- **handleSuccess** (function): Callback function to handle success, executed after a successful reaction.

## Notes

- **Related Components**: `CommentReactionButton`, `CommentItem`.

## Example Usage

```javascript
import ReactionButton from '../ReactionButton'

export const DefaultComments = (target) => (
<ReactionButton
target={target}
reactionType="LIKE"
handleError={() => console.log('Error handling reaction')}
handleSuccess={() => console.log('Successfully handled reaction')}
/>
)
Comment on lines +32 to +42
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance the example with TypeScript and best practices

The current example could be more comprehensive by including TypeScript types and demonstrating the children render prop pattern.

Consider updating the example:

-```javascript
+```typescript
 import ReactionButton from '../ReactionButton'
+import type { ReactionButton_target$key } from './__generated__/ReactionButton_target.graphql'
+
+interface Props {
+  target: ReactionButton_target$key
+}

-export const DefaultComments = (target) => (
+export const DefaultComments: React.FC<Props> = ({ target }) => (
   <ReactionButton
     target={target}
     reactionType="LIKE"
-    handleError={() => console.log('Error handling reaction')}
-    handleSuccess={() => console.log('Successfully handled reaction')}
+    handleError={(error) => {
+      console.error('Error handling reaction:', error)
+      // Show error toast or handle appropriately
+    }}
+    handleSuccess={() => {
+      console.log('Successfully handled reaction')
+      // Refetch data or update UI
+    }}
+  >
+    {({ handleReaction, isLoading, target }) => (
+      <button
+        onClick={handleReaction}
+        disabled={isLoading}
+      >
+        {isLoading ? 'Loading...' : `Like (${target.likeCount})`}
+      </button>
+    )}
   />
 )

Original file line number Diff line number Diff line change
Expand Up @@ -7,60 +7,6 @@ import { mockResolvers } from './mockResolvers'
const meta: Meta<typeof ReactionButton> = {
title: '@baseapp-frontend | components/Shared/ReactionButton',
component: ReactionButtonWithQuery,
tags: ['autodocs'],
argTypes: {
target: {
name: 'target',
description: 'The target data for the reaction button.',
control: 'object',
table: {
type: {
summary: 'ReactionButton_target$key',
},
},
},
reactionType: {
name: 'reactionType',
description: 'Type of reaction (e.g., LIKE, DISLIKE).',
control: 'text',
table: {
type: {
summary: 'ReactionTypes',
},
},
},
children: {
name: 'children',
description: 'Function to render the children components with reaction handlers.',
control: false,
table: {
type: {
summary:
'(props: { handleReaction: () => void, isLoading: boolean, target: ReactionButton_target$data }) => ReactElement | null',
},
},
},
handleError: {
name: 'handleError',
description: 'Callback function to handle errors.',
control: false,
table: {
type: {
summary: '() => void',
},
},
},
handleSuccess: {
name: 'handleSuccess',
description: 'Callback function to handle success.',
control: false,
table: {
type: {
summary: '() => void',
},
},
},
},
}

export default meta
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,6 @@ import SocialInputWithForm from './SocialInputWithForm'
const meta: Meta<typeof SocialInput> = {
title: '@baseapp-frontend | components/Shared/SocialInput',
component: SocialInputWithForm,
tags: ['autodocs'],
argTypes: {
placeholder: {
description: 'Placeholder for the input field.',
control: { type: 'text' },
defaultValue: 'Message...',
},
autoFocusInput: {
description: 'Automatically focus the input field.',
control: { type: 'boolean' },
defaultValue: false,
},
isLoading: {
description: 'Indicates whether the form submission is in progress.',
control: { type: 'boolean' },
defaultValue: false,
},
isReply: {
description: 'Indicates if the message is a reply.',
control: { type: 'boolean' },
defaultValue: false,
},
replyTargetName: {
description: 'Name of the person being replied to.',
control: { type: 'text' },
},
onCancelReply: {
description: 'Callback when the reply is canceled.',
action: 'cancelReply',
},
},
}

export default meta
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import SocialUpsertActions from '..'
const meta: Meta<typeof SocialUpsertActions> = {
title: '@baseapp-frontend | components/Shared/SocialUpsertActions',
component: SocialUpsertActions,
tags: ['autodocs'],
}

export default meta
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,6 @@ import Timestamp from '..'
const meta: Meta<typeof Timestamp> = {
title: '@baseapp-frontend | components/Shared/Timestamp',
component: Timestamp,
tags: ['autodocs'],
argTypes: {
date: {
name: 'date',
description: 'The date to be formatted.',
control: 'text',
table: {
type: {
summary: 'string',
},
},
},
},
}

export default meta
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,6 @@ import CommentCreateWithProvider from './CommentCreateWithProvider'
const meta: Meta<typeof CommentCreate> = {
title: '@baseapp-frontend | components/Comments/CommentCreate',
component: CommentCreateWithProvider,
tags: ['autodocs'],
argTypes: {
targetObjectId: {
description: 'The ID of the target object for the comment.',
control: 'text',
table: {
type: {
summary: 'string',
},
},
},
autoFocusInput: {
description: 'Whether the input should auto-focus on mount.',
control: 'boolean',
table: {
type: {
summary: 'boolean',
},
},
},
profileId: {
description: 'ID of the profile creating the comment.',
control: 'text',
table: {
type: {
summary: 'string',
},
},
},
SocialInput: {
description: 'Overrides the SocialInput component.',
control: false,
table: {
type: {
summary: 'FC<SocialInputProps>',
},
},
},
SocialInputProps: {
description: 'See SocialInput`s story for more details.',
table: {
type: {
summary: 'Partial<SocialInputProps>',
},
},
},
},
}

export default meta
Expand Down
Loading
Loading