├── CI
└── CD
│ └── github-actions.md
├── IDEs
└── VSCode
│ ├── vscode-extensions.md
│ └── vscode-styling.md
├── README.md
├── architecture-approaches
├── assets
│ ├── diagram1.webp
│ ├── diagram2.webp
│ └── diagram3.webp
├── atomic.md
├── feature-based.md
├── feature-sliced.md
├── modular.md
└── module-federation.md
├── auth
└── aws-cognito.md
├── data-fetching
├── axios.md
├── react-query.md
└── swr.md
├── forms
├── formik.md
├── react-hook-form.md
├── storing-in-local-storage.md
└── validation.md
├── git
├── pull_request_template.md
├── rebase.md
└── squash-merge.md
├── images
├── optimizations.md
└── svg.md
├── infinite-scroll
└── infinite-scroll.md
├── internationalization
├── i18next.md
├── lingui-js.md
└── react-intl.md
├── monitoring
└── sentry.md
├── notifications
├── circle-ci-slack.md
└── jira-github.md
├── roles-and-permissions
└── roles-and-permissions.md
├── router
└── leave-modal.md
├── ssr
├── general.md
└── nextjs
│ ├── assets
│ └── basic-auth.png
│ ├── basic-auth.md
│ ├── next-js-13.md
│ └── overview.md
├── state-management
├── context
│ ├── overview.md
│ ├── react-context-useReducer.md
│ └── ref-based-context-api.md
└── redux-toolkit
│ ├── overview.md
│ └── rtk-query.md
├── styling
├── MUI.md
├── dark-mode.md
├── general-recommendations.md
└── styled-components.md
└── ui-components
├── WYSIWYG
└── tip-tap.md
├── date-time-pickers.md
├── otp-input.md
├── simple-dialog.md
├── textarea-with-emoji.md
├── tree-select.md
└── tree-view-select.md
/IDEs/VSCode/vscode-extensions.md:
--------------------------------------------------------------------------------
1 | # Most popular extensions for VS Code
2 |
3 | 1. [GitLens](#gitlens)
4 | 2. [Import Cost](#import-cost)
5 | 3. [Auto Rename Tag](#auto-rename-tag)
6 | 4. [Code Spell Checker](#code-spell-checker)
7 | 5. [Prettier](#prettier)
8 | 6. [GitHub Copilot](#github-copilot)
9 | 7. [IntelliCode](#intellicode)
10 | 8. [Wallaby](#wallaby)
11 | 9. [Auto Import](#auto-import)
12 | 10. [Clipboard History](#clipboard-history)
13 | 11. [Git History](#git-history)
14 | 12. [json](#json)
15 | 13. [Mithril Emmet](#mithril-emmet)
16 | 14. [Window Colors](#window-colors)
17 |
18 | ## GitLens
19 |
20 | GitLens is a powerful and feature-rich extension for Visual Studio Code (VsCode) that enhances the built-in Git integration of the editor. It provides a wide range of tools and features to help developers navigate, analyze, and understand Git repositories directly from within the VsCode interface.
21 |
22 | 
23 |
24 | [Link to download](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens "Link to download")
25 |
26 | ## Import Cost
27 |
28 | Extension provides valuable information about the size of imported JavaScript and TypeScript modules. It helps developers understand the impact of their imports on the overall bundle size of their applications.
29 |
30 | 
31 |
32 | [Link to download](https://marketplace.visualstudio.com/items?itemName=wix.vscode-import-cost "Link to download")
33 |
34 | ## Auto Rename Tag
35 |
36 | Simplifies the process of renaming HTML or XML tags in your code. When you rename the opening tag of an element, this extension automatically updates the corresponding closing tag with the same name, ensuring that your code remains valid and syntactically correct.
37 |
38 | 
39 |
40 | [Link to download](https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag "Link to download")
41 |
42 | ## Code Spell Checker
43 |
44 | The extension assists developers in finding and correcting spelling mistakes in their code and comments. As the name suggests, it focuses on checking the spelling of words used in programming languages and documentation, making it a valuable tool for maintaining code quality and readability.
45 |
46 | 
47 |
48 | [Link to download](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker "Link to download")
49 |
50 | ## Prettier
51 |
52 | Prettier is a popular code formatting tool that helps developers automatically format their code to adhere to a consistent and opinionated code style. It supports multiple programming languages, including JavaScript, TypeScript, CSS, HTML, JSON, and more.
53 |
54 | [Link to download](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode "Link to download")
55 |
56 | ## GitHub Copilot
57 |
58 | GitHub Copilot is an AI-powered coding assistant developed by GitHub in collaboration with OpenAI. It is designed to help developers write code more efficiently by providing intelligent code suggestions and completions. GitHub Copilot is built on top of OpenAI's GPT-3 language model, which allows it to understand context and generate relevant code suggestions based on the current code context and the natural language descriptions provided by the developer.
59 |
60 | 
61 |
62 | [Link to download](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot "Link to download")
63 |
64 | ## IntelliCode
65 |
66 | IntelliCode is an AI-assisted feature in VsCode developed by Microsoft. It uses machine learning algorithms to offer intelligent suggestions and code completions as you write code. IntelliCode aims to improve productivity by providing contextually relevant code suggestions based on patterns learned from large code repositories.
67 |
68 | 
69 |
70 | [Link to download](https://marketplace.visualstudio.com/items?itemName=VisualStudioExptTeam.vscodeintellicode "Link to download")
71 |
72 | ## Wallaby
73 |
74 | Wallaby.js is a developer productivity tool that runs your JavaScript and TypeScript tests immediately as you type, highlighting results in your IDE right next to your code.
75 |
76 | 
77 |
78 | [Link to download](https://marketplace.visualstudio.com/items?itemName=WallabyJs.wallaby-vscode "Link to download")
79 |
80 | ## Auto Import
81 |
82 | Auto Import automatically imports modules and components in your JavaScript (or TypeScript) code as you type. It can significantly improve your coding workflow by saving time and reducing errors when dealing with imports.
83 |
84 | 
85 |
86 | [Link to download](https://marketplace.visualstudio.com/items?itemName=steoates.autoimport "Link to download")
87 |
88 | ## Clipboard History
89 |
90 | This extension provides a simple clipboard history manager that keeps track of your copied items and allows you to easily paste any of them.
91 |
92 | 
93 |
94 | [Link to download](https://marketplace.visualstudio.com/items?itemName=Anjali.clipboard-history "Link to download")
95 |
96 | ## Git History
97 |
98 | Git History (git log): This extension provides an interactive and user-friendly interface to explore the Git history of your project. It allows you to:
99 |
100 | - View commit details such as commit messages, authors, dates, and commit hashes.
101 | - See the changes introduced in each commit.
102 | - Compare changes between commits.
103 | - View the commit history in a tree or linear format.
104 | - Perform Git actions like checkout, reset, and more directly from the history view.
105 |
106 | 
107 |
108 | [Link to download](https://marketplace.visualstudio.com/items?itemName=donjayamanne.githistory "Link to download")
109 |
110 | ## json
111 |
112 | This extension adds json support for Visual Studio Code.
113 |
114 | 
115 |
116 | [Link to download](https://marketplace.visualstudio.com/items?itemName=ZainChen.json "Link to download")
117 |
118 | ## markdownlint
119 |
120 | This extension provides linting capabilities for Markdown files within the editor. It helps maintain consistent and error-free Markdown formatting, making it easier to write and read Markdown content.
121 |
122 | [Link to download](https://marketplace.visualstudio.com/items?itemName=ZainChen.json "Link to download")
123 |
124 | ## Mithril Emmet
125 |
126 | Emmet is a popular tool for web developers that provides a set of powerful shortcuts for writing HTML and CSS code more quickly and efficiently. It allows you to use abbreviations to generate complete HTML/CSS code snippets. It's not tied to any particular JavaScript framework like Mithril, but it can be used with any web development stack.
127 |
128 | 
129 |
130 | [Link to download](https://marketplace.visualstudio.com/items?itemName=FallenMax.mithril-emmet "Link to download")
131 |
132 | ## Window Colors
133 |
134 | Uniquely and automatically colors each VSCode window.
135 |
136 | 
137 |
138 | [Link to download](https://marketplace.visualstudio.com/items?itemName=stuart.unique-window-colors "Link to download")
139 |
--------------------------------------------------------------------------------
/IDEs/VSCode/vscode-styling.md:
--------------------------------------------------------------------------------
1 | # Styling
2 |
3 | 1. [General information](#general)
4 | 2. [Theme change](#theme-change)
5 | 3. [Custom theme change](#custom-theme-change)
6 | 4. [Font change](#font-change)
7 | 5. [Terminal theme change](#terminal-theme)
8 | 6. [Terminal font change](#terminal-font)
9 |
10 | ## General information
11 |
12 | 1. **Personalization**: IDE styling allows developers to customize the appearance of their coding environment to match their preferences and workflow. Everyone has different tastes, and having a personalized theme can create a more enjoyable coding experience.
13 |
14 | 2. **Reduced Eye Strain**: A well-designed theme with suitable colors and contrast can reduce eye strain and fatigue during long coding sessions. Developers can choose color schemes that are easier on their eyes, making it more comfortable to work for extended periods.
15 |
16 | 3. **Improved Readability**: A well-chosen theme can improve code readability, making it easier to spot syntax errors, keywords, and different elements in the code. Clear distinction between different code elements can enhance code comprehension and navigation.
17 |
18 | 4. **Focus and Productivity**: A clean and visually appealing IDE can help developers stay focused and productive. By minimizing distractions and creating a pleasant work environment, developers can concentrate more on coding tasks.
19 |
20 | 5. **Identification and Error Detection**: IDE styling allows developers to set distinct colors for various code elements like comments, strings, functions, etc. This makes it easier to identify different parts of the code and quickly spot errors and potential issues.
21 |
22 | 6. **Consistency**: IDE styling can be part of a developer's standard setup, ensuring a consistent and familiar coding environment across different machines and projects. This can aid in quickly adapting to new development tasks and projects.
23 |
24 | 7. **Branding and Aesthetics**: For developers working in a team or showcasing their work to others, a consistent and well-designed IDE theme can contribute to the overall aesthetics and branding of their projects or organization.
25 |
26 | 8. **Motivation and Inspiration**: A visually appealing IDE with a favorite theme can be motivating and inspiring for developers. It can create a sense of ownership and pride in their coding environment.
27 |
28 | Overall, IDE styling is not just about aesthetics but also about optimizing the development experience, reducing visual strain, and creating a coding environment that suits an individual developer's preferences and needs. With the numerous themes and customization options available, developers can choose the one that best enhances their productivity and enjoyment while coding.
29 |
30 | In this cookbook chapter we pay attention to installation of a custom theme and fonts for editor and for terminal. It could help you to improve your efficiency as a developer and improve code readability.
31 |
32 | ## Theme change
33 |
34 | 1. Open VS Code: Launch Visual Studio Code on your computer.
35 | 2. Access the Command Palette: Use the keyboard shortcut `Ctrl+Shift+P` (Windows/Linux) or `Cmd+Shift+P` (Mac) to open the Command Palette.
36 | 3. Search for "Preferences: Color Theme": In the Command Palette, start typing "Preferences: Color Theme," and it should suggest the command as you type. Once you see it, select the option to open the Color Theme menu.
37 | 4. Choose a new theme: In the Color Theme menu, you'll see a list of available themes. Use the arrow keys to navigate through the list, and you'll see a live preview of each theme as you select it.
38 | 5. Apply the selected theme: Once you find a theme you like, press `Enter` to apply it. VS Code will immediately switch to the new theme.
39 |
40 | If you have installed additional themes from the VS Code Marketplace, they will also appear in the Color Theme menu for you to choose from.
41 |
42 | Additionally, you can also access the Color Theme menu through the Settings:
43 |
44 | 1. Open the Settings: Click on the gear icon (`⚙️`) in the lower-left corner of the VS Code window, and select "Settings" from the menu. Alternatively, you can use the keyboard shortcut `Ctrl+,` (Windows/Linux) or `Cmd+,` (Mac) to open Settings.
45 | 2. Navigate to Color Theme: In the Settings, use the search bar to look for "Color Theme." Click on the dropdown menu below "Color Theme" to select your desired theme.
46 | 3. Apply the selected theme: Once you choose the theme, the editor will immediately update to reflect the new theme.
47 |
48 | ## Custom theme change
49 |
50 | Install an extension with the custom theme. E.g., we want to update our current theme to the Night Wolf theme.
51 | Navigate to this [extenstion](https://marketplace.visualstudio.com/items?itemName=MaoSantaella.night-wolf) in the extensions tab and install this extension to your IDE.
52 |
53 | Repeat actions from the previous step and update your theme in the Settings tab.
54 |
55 | ## Font change
56 |
57 | 1. Open VS Code: Launch Visual Studio Code on your computer.
58 | 2. Access the Settings: Click on the gear icon (`⚙️`) in the lower-left corner of the VS Code window, and select "Settings" from the menu. Alternatively, you can use the keyboard shortcut `Ctrl+,` (Windows/Linux) or `Cmd+,` (Mac) to open Settings.
59 | 3. Search for "Font": In the Settings, you'll see a search bar at the top. Type "Font" in the search bar to filter the settings related to the font.
60 | 4. Look for "Editor: Font Family": In the search results, you should find the setting called "Editor: Font Family." This setting defines the font used in the editor.
61 | 5. Edit the Font Family setting: Click on the pencil icon to the left of "Editor: Font Family" to edit it. You can now enter the name of the font you want to use for the editor. You can also specify a fallback font in case the primary font is not available on your system.
62 | For example, you can set the font to "Consolas, 'Courier New', monospace" to use the "Consolas" font if available, and if not, it will use "Courier New" as a fallback.
63 | 6. Save the changes: Once you've entered your desired font or font family, press `Enter` to save the changes.
64 | 7. Optional: You might need to restart VS Code for the font changes to take effect fully.
65 |
66 | After following these steps, you should see the new font being used in the editor. Feel free to experiment with different fonts and font families until you find one that suits your preferences and enhances your coding experience.
67 |
68 | ## Terminal theme change
69 |
70 | For changing your terminal theme we use [Oh My Posh](https://ohmyposh.dev/) app.
71 | In order to use it, follow these steps:
72 |
73 | 1. Install this application on your computer. You can find instructions [here](https://ohmyposh.dev/docs/installation/macos).
74 | 2. Create a new file with your custom theme. You can find instructions [here](https://ohmyposh.dev/docs/installation/customize).
75 | 3. Choose your custom theme [here](https://ohmyposh.dev/docs/themes).
76 | 4. For example, you decided to use the `powerlevel10k_rainbow` theme.
77 | 5. Navigate to the themes [list](https://github.com/JanDeDobbeleer/oh-my-posh/tree/main/themes).
78 | 6. Find your theme [here](https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/powerlevel10k_rainbow.omp.json).
79 | 7. Copy JSON and paste to your configuration file which you created in previous steps.
80 | 8. Notice that your terminal has changed.
81 |
82 | ## Terminal font change
83 |
84 | To change fonts you should complete installation of the Oh My Posh app on your computer.
85 | Then follow this [guide](https://ohmyposh.dev/docs/installation/fonts) for the font installation.
86 |
87 | For example, you decided to choose SpaceMono NF font.
88 | In order to use it, follow these steps:
89 |
90 | 1. Download this font package from Nerd Fonts [here](https://github.com/ryanoasis/nerd-fonts/tree/master/patched-fonts/SpaceMono).
91 | 2. Install each of the font style to your computer (open each of the file and click the `Install` button).
92 | 3. Search for "Terminal Font Family": In Settings, you'll see a search bar at the top. Type "Terminal Font Family" in the search bar to filter the settings related to the terminal font.
93 |
94 | Here is a screenshot with changing terminal font:
95 | 
96 |
97 | Also, you can modify it in VS Code `settings.json` file:
98 | 
99 |
100 | After changing theme and font of your terminal in VS Code, it will look like this one on the screenshot below:
101 | 
102 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Table of contents
2 |
3 | This document compiles industry best practices, proven strategies, and valuable insights to empower developers in their front-end projects.
4 | Using information from chapters of this document could help you save time during the development process and during the work with estimations.
5 | This cookbook is based on the experience of the whole Uptech front-end team during our work on different projects over the last 2 years.
6 | Also, it could be helpful for newcomers who don't have relevant experience with some technologies that we use on a regular basis.
7 |
8 | - [Architecture](https://github.com/uptechteam/fe-cookbook/tree/main/architecture-approaches)
9 | - [Atomic](https://github.com/uptechteam/fe-cookbook/blob/main/architecture-approaches/atomic.md)
10 | - [Feature based](https://github.com/uptechteam/fe-cookbook/blob/main/architecture-approaches/feature-based.md)
11 | - [Feature sliced](https://github.com/uptechteam/fe-cookbook/blob/main/architecture-approaches/feature-sliced.md)
12 | - [Modular](https://github.com/uptechteam/fe-cookbook/blob/main/architecture-approaches/modular.md)
13 | - [Module federation](https://github.com/uptechteam/fe-cookbook/blob/main/architecture-approaches/module-federation.md)
14 | - [Authentication](https://github.com/uptechteam/fe-cookbook/tree/main/auth)
15 | - [AWS Cognito](https://github.com/uptechteam/fe-cookbook/blob/main/auth/aws-cognito.md)
16 | - [Data fetching](https://github.com/uptechteam/fe-cookbook/tree/main/data-fetching)
17 | - [Axios](https://github.com/uptechteam/fe-cookbook/blob/main/data-fetching/axios.md)
18 | - [React Query](https://github.com/uptechteam/fe-cookbook/blob/main/data-fetching/react-query.md)
19 | - [SWR](https://github.com/uptechteam/fe-cookbook/blob/main/data-fetching/swr.md)
20 | - [Forms](https://github.com/uptechteam/fe-cookbook/tree/main/forms)
21 | - [Formik](https://github.com/uptechteam/fe-cookbook/blob/main/forms/formik.md)
22 | - [React Hook Form](https://github.com/uptechteam/fe-cookbook/blob/main/forms/react-hook-form.md)
23 | - [Storing form data in localStorage](https://github.com/uptechteam/fe-cookbook/blob/main/forms/storing-in-local-storage.md)
24 | - [Validation](https://github.com/uptechteam/fe-cookbook/blob/main/forms/validation.md)
25 | - [Git](https://github.com/uptechteam/fe-cookbook/tree/main/git)
26 | - [Rebase](https://github.com/uptechteam/fe-cookbook/blob/main/git/rebase.md)
27 | - [Squash & Merge](https://github.com/uptechteam/fe-cookbook/blob/main/git/squash-merge.md)
28 | - [Pull request template create](https://github.com/uptechteam/fe-cookbook/blob/main/git/pull_request_template.md)
29 | - [IDEs](https://github.com/uptechteam/fe-cookbook/tree/main/IDEs)
30 | - [VSCode](https://github.com/uptechteam/fe-cookbook/tree/main/IDEs/VSCode)
31 | - [Extensions](https://github.com/uptechteam/fe-cookbook/blob/main/IDEs/VSCode/vscode-extensions.md)
32 | - [Styling](https://github.com/uptechteam/fe-cookbook/blob/main/IDEs/VSCode/vscode-styling.md)
33 | - [Images](https://github.com/uptechteam/fe-cookbook/tree/main/images)
34 | - [Optimizations](https://github.com/uptechteam/fe-cookbook/blob/main/images/optimizations.md)
35 | - [SVG](https://github.com/uptechteam/fe-cookbook/blob/main/images/svg.md)
36 | - [Infinite scroll](https://github.com/uptechteam/fe-cookbook/blob/main/infinite-scroll/)
37 | - [Intersection Observer API](https://github.com/uptechteam/fe-cookbook/blob/main/infinite-scroll/infinite-scroll.md)
38 | - [Internationalization](https://github.com/uptechteam/fe-cookbook/tree/main/internationalization)
39 | - [i18next](https://github.com/uptechteam/fe-cookbook/blob/main/internationalization/i18next.md)
40 | - [lingui-js](https://github.com/uptechteam/fe-cookbook/blob/main/internationalization/lingui-js.md)
41 | - [react-intl](https://github.com/uptechteam/fe-cookbook/blob/main/internationalization/react-intl.md)
42 | - [Monitoring](https://github.com/uptechteam/fe-cookbook/tree/main/monitoring)
43 | - [Sentry](https://github.com/uptechteam/fe-cookbook/tree/main/monitoring/sentry.md)
44 | - [Notifications](https://github.com/uptechteam/fe-cookbook/tree/main/notifications)
45 | - [CircleCI to Slack](https://github.com/uptechteam/fe-cookbook/blob/main/notifications/circle-ci-slack.md)
46 | - [JIRA to GitHub](https://github.com/uptechteam/fe-cookbook/blob/main/notifications/jira-github.md)
47 | - [Roles and permissions](https://github.com/uptechteam/fe-cookbook/tree/main/roles-and-permissions)
48 | - [Common approaches](https://github.com/uptechteam/fe-cookbook/blob/main/roles-and-permissions/roles-and-permissions.md)
49 | - [Routing](https://github.com/uptechteam/fe-cookbook/tree/main/router)
50 | - [Leave modal logic](https://github.com/uptechteam/fe-cookbook/blob/main/router/leave-modal.md)
51 | - [SSR](https://github.com/uptechteam/fe-cookbook/tree/main/ssr)
52 | - [Next.js](https://github.com/uptechteam/fe-cookbook/tree/main/ssr/nextjs)
53 | - [Basic Auth](https://github.com/uptechteam/fe-cookbook/blob/main/ssr/nextjs/basic-auth.md)
54 | - [Overview](https://github.com/uptechteam/fe-cookbook/blob/main/ssr/nextjs/overview.md)
55 | - [Next.js 13](https://github.com/uptechteam/fe-cookbook/blob/main/ssr/nextjs/next-js-13.md)
56 | - [General](https://github.com/uptechteam/fe-cookbook/blob/main/ssr/general.md)
57 | - [State management](https://github.com/uptechteam/fe-cookbook/tree/main/state-management)
58 | - [React Context API](https://github.com/uptechteam/fe-cookbook/tree/main/state-management/context)
59 | - [Overview](https://github.com/uptechteam/fe-cookbook/blob/main/state-management/context/overview.md)
60 | - [React Context API + useReducer hook](https://github.com/uptechteam/fe-cookbook/blob/main/state-management/context/react-context-useReducer.md)
61 | - [Ref-based React Context API](https://github.com/uptechteam/fe-cookbook/blob/main/state-management/context/ref-based-context-api.md)
62 | - [Redux Toolkit](https://github.com/uptechteam/fe-cookbook/tree/main/state-management/redux-toolkit)
63 | - [Overview](https://github.com/uptechteam/fe-cookbook/blob/main/state-management/redux-toolkit/overview.md)
64 | - [RTK Query](https://github.com/uptechteam/fe-cookbook/blob/main/state-management/redux-toolkit/rtk-query.md)
65 | - [Styling](https://github.com/uptechteam/fe-cookbook/tree/main/styling)
66 | - [MUI](https://github.com/uptechteam/fe-cookbook/blob/main/styling/MUI.md)
67 | - [Dark mode setup](https://github.com/uptechteam/fe-cookbook/blob/main/styling/dark-mode.md)
68 | - [General recommendations](https://github.com/uptechteam/fe-cookbook/blob/main/styling/general-recommendations.md)
69 | - [Styled Components](https://github.com/uptechteam/fe-cookbook/blob/main/styling/styled-components.md)
70 | - [UI components](https://github.com/uptechteam/fe-cookbook/tree/main/ui-components)
71 | - [Date & time pickers](https://github.com/uptechteam/fe-cookbook/blob/main/ui-components/date-time-pickers.md)
72 | - [OTP input](https://github.com/uptechteam/fe-cookbook/blob/main/ui-components/otp-input.md)
73 | - [Textarea with emoji](https://github.com/uptechteam/fe-cookbook/blob/main/ui-components/textarea-with-emoji.md)
74 | - [Tree view multi-select](https://github.com/uptechteam/fe-cookbook/blob/main/ui-components/tree-select.md)
75 | - [Tree view select](https://github.com/uptechteam/fe-cookbook/blob/main/ui-components/tree-view-select.md)
76 | - [WYSIWYG](https://github.com/uptechteam/fe-cookbook/tree/main/ui-components/WYSIWYG)
77 | - [Tiptap](https://github.com/uptechteam/fe-cookbook/blob/main/ui-components/WYSIWYG/tip-tap.md)
78 |
--------------------------------------------------------------------------------
/architecture-approaches/assets/diagram1.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uptechteam/fe-cookbook/8d9a76022430daff58629e264dfcd23b2e281b5e/architecture-approaches/assets/diagram1.webp
--------------------------------------------------------------------------------
/architecture-approaches/assets/diagram2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uptechteam/fe-cookbook/8d9a76022430daff58629e264dfcd23b2e281b5e/architecture-approaches/assets/diagram2.webp
--------------------------------------------------------------------------------
/architecture-approaches/assets/diagram3.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uptechteam/fe-cookbook/8d9a76022430daff58629e264dfcd23b2e281b5e/architecture-approaches/assets/diagram3.webp
--------------------------------------------------------------------------------
/architecture-approaches/atomic.md:
--------------------------------------------------------------------------------
1 | # Atomic design
2 |
3 | 1. [General information](#general-information)
4 | 2. [Structure example](#structure-example)
5 |
6 | ## General information
7 |
8 | The main idea behind Atomic Design is to break down the user interface into smaller, reusable components that can be combined to create more complex UI elements and pages. The methodology is inspired by chemistry's atomic structure, where atoms combine to form molecules, which in turn combine to form organisms, and so on.
9 |
10 | The five stages of Atomic Design are:
11 |
12 | 1. **Atoms**:
13 | Atoms are the smallest and simplest UI elements, such as buttons, input fields, labels, and icons. They are the building blocks of all other UI components and should be designed to be highly reusable.
14 |
15 | 2. **Molecules**:
16 | Molecules are combinations of two or more atoms that work together to create a more significant, reusable component. For example, a form input with a label and validation message is a molecule formed by combining several atoms.
17 |
18 | 3. **Organisms**:
19 | Organisms are more complex components that combine molecules and atoms to form functional and recognizable sections of a user interface. Examples of organisms could be a header, footer, or a card component with various content elements.
20 |
21 | 4. **Templates**:
22 | Templates represent the layout of a page and define the placement of organisms within the overall structure. They provide a framework for organizing content on a specific type of page.
23 |
24 | 5. **Pages**:
25 | Pages are instances where templates are filled with actual content to create fully functioning web pages or application screens.
26 |
27 | The benefit of Atomic Design is that it promotes consistency, scalability, and reusability. By breaking down the UI into smaller components and adhering to a consistent naming and organizational structure, design and development teams can work more efficiently. Changes to individual atoms or molecules automatically propagate to higher-level components, ensuring a coherent user experience.
28 |
29 | Atomic Design is not tied to any specific technology or framework and can be used with any frontend development stack, including React, Angular, or Vue.js. It's a design methodology that complements component-based architecture and helps teams create well-structured, maintainable, and consistent UI systems.
30 |
31 | ## Structure example
32 |
33 | - src/
34 |
35 | - atoms/
36 |
37 | - button/
38 | - Button.tsx
39 | - input/
40 | - Input.tsx
41 | - icon/
42 | - Icon.tsx
43 |
44 | - molecules/
45 |
46 | - form-input/
47 | - FormInput.tsx
48 | - card/
49 | - Card.tsx
50 |
51 | - organisms/
52 |
53 | - header/
54 | - Header.tsx
55 | - footer/
56 | - Footer.tsx
57 |
58 | - templates/
59 |
60 | - blog-post-template/
61 | - BlogPostTemplate.tsx
62 | - product-page-template/
63 | - ProductPageTemplate.tsx
64 |
65 | - pages/
66 |
67 | - home-page/
68 | - HomePage.tsx
69 | - about-page/
70 | - AboutPage.tsx
71 | - contact-page/
72 | - ContactPage.tsx
73 |
74 | - styles/
75 |
76 | - global.css
77 | - variables.css
78 | - mixins.css
79 | - theme.ts
80 |
81 | - utils/
82 |
83 | - api.ts
84 | - helpers.ts
85 | - validation.ts
86 |
87 | - redux/
88 |
89 | - actions/
90 | - actionTypes.ts
91 | - userActions.ts
92 | - reducers/
93 | - userReducer.ts
94 | - store.ts
95 |
96 | - assets/
97 |
98 | - images/
99 | - logo.png
100 | - background.jpg
101 | - icons/
102 | - menu.svg
103 | - close.svg
104 |
105 | - index.tsx
106 | - App.tsx
107 |
--------------------------------------------------------------------------------
/architecture-approaches/feature-based.md:
--------------------------------------------------------------------------------
1 | # Feature based
2 |
3 | 1. [General information](#general-information)
4 | 2. [Structure example](#structure-example)
5 |
6 | ## General information
7 |
8 | Feature-based architecture is an architectural approach that organizes code and project structure around the features or functionalities of an application rather than grouping them by the traditional architecture layers (e.g., presentation, business logic, data access). In a feature-based architecture, each feature of the application is treated as a self-contained module, containing all the necessary components, business logic, and data handling related to that specific feature.
9 |
10 | The main characteristics of a feature-based architecture include:
11 |
12 | 1. **Modularity**: Features are self-contained and isolated from one another. This makes it easier to understand, maintain, and test individual features without affecting the rest of the application.
13 |
14 | 2. **Loose Coupling**: Features are loosely coupled, meaning they interact with each other through well-defined interfaces or APIs. This reduces interdependencies and helps to avoid code entanglement.
15 |
16 | 3. **Scalability**: New features can be added to the application without disrupting existing features. Each feature can be developed and tested independently, making it easier to scale the application as it grows.
17 |
18 | 4. **Reusability**: Features can be reused in other parts of the application or even in different projects. This promotes code reuse and saves development time.
19 |
20 | 5. **Collaboration**: In larger projects, different teams can work on different features simultaneously, which improves development efficiency and enables parallel work.
21 |
22 | 6. **Domain-Driven Design (DDD) alignment**: Feature-based architecture aligns well with the principles of Domain-Driven Design, where the codebase is organized based on the business domain.
23 |
24 | Feature-based architecture is commonly used in modern frontend development, especially in large-scale web applications. It is often seen in frameworks like Angular, where Angular Modules provide a natural way to create feature-based architectures. However, it can also be applied to other frontend frameworks, such as React and Vue.js.
25 |
26 | With feature-based architecture, developers can focus on building and maintaining specific features in isolation, leading to a more maintainable and scalable codebase. It helps to avoid the problem of "spaghetti code" that can occur in monolithic architectures, where features and functionalities are tightly coupled, making it challenging to modify or extend the application over time.
27 |
28 | ## Structure example
29 |
30 | - src/
31 |
32 | - features/
33 |
34 | - user/
35 | - components/
36 | - UserList.tsx
37 | - UserDetail.tsx
38 | - containers/
39 | - UserListContainer.tsx
40 | - UserDetailContainer.tsx
41 | - actions/
42 | - userActionTypes.ts
43 | - userActions.ts
44 | - reducers/
45 | - userReducer.ts
46 | - services/
47 | - userService.ts
48 | - products/
49 | - components/
50 | - ProductList.tsx
51 | - ProductDetail.tsx
52 | - containers/
53 | - ProductListContainer.tsx
54 | - ProductDetailContainer.tsx
55 | - actions/
56 | - productActionTypes.ts
57 | - productActions.ts
58 | - reducers/
59 | - productReducer.ts
60 | - services/
61 | - productService.ts
62 |
63 | - shared/
64 |
65 | - components/
66 | - Header.tsx
67 | - Footer.tsx
68 |
69 | - utils/
70 |
71 | - api.ts
72 | - auth.ts
73 | - validation.ts
74 |
75 | - redux/
76 |
77 | - store.ts
78 |
79 | - assets/
80 |
81 | - images/
82 | - logo.png
83 | - background.jpg
84 | - icons/
85 | - menu.svg
86 | - close.svg
87 |
88 | - App.tsx
89 |
90 | In this example, we have organized the codebase using a feature-based architecture, where each feature (e.g., `user`, `products`) is treated as a separate module within the `features` directory.
91 |
92 | Each feature directory contains subdirectories to organize different aspects of the feature:
93 |
94 | - `components/`: Contains presentational components related to the feature.
95 | - `containers/`: Contains container components that connect the presentational components to the Redux store and handle logic.
96 | - `actions/`: Holds action types and action creators specific to the feature.
97 | - `reducers/`: Contains reducers for managing the state of the feature.
98 | - `services/`: Contains service files related to the feature (e.g., API calls, data handling).
99 |
100 | The `shared/` directory contains shared components that can be used across different features.
101 |
102 | The `utils/` directory holds utility files, such as API functions, authentication functions, and validation utilities.
103 |
104 | The `redux/` directory contains the Redux store configuration.
105 |
106 | The `assets/` directory holds images and icons used in the application.
107 |
108 | Please note that this is a simplified example, and in a real-world project, the file structure may be more extensive, including additional directories for routes, constants, tests, and more. The key idea behind a feature-based architecture is to group related functionality together in a modular and isolated way, leading to a more maintainable and scalable codebase.
109 |
--------------------------------------------------------------------------------
/architecture-approaches/feature-sliced.md:
--------------------------------------------------------------------------------
1 | # Feature sliced
2 |
3 | 1. [What is Feature Sliced Design (FSD)?](<#what-is-feature-sliced-design-(FSD)>)
4 | 2. [Assemble correctly from Childhood!](#assemble-correctly-from-childhood)
5 | 3. [Structure example](#structure-example)
6 |
7 | ## What is Feature Sliced Design (FSD)?
8 |
9 | **“Feature Sliced Design”** — architectural design methodology for Front-End applications, a design approach where a product’s features are divided into separate, standalone components, or “slices”. Each slice is then designed and developed independently, allowing for greater flexibility, modularity, and scalability in the design process. This approach is often used in software development and can be applied to the design of web or mobile applications, as well as other types of software products.
10 |
11 | 
12 |
13 | We figured out that idea behind FSD is to break down a complex product into smaller, more manageable pieces in each “Layer”. Each “Layer” might contain other manageable pieces — “Slices”. “Slaces” in turn may have “Segments”.
14 |
15 | 
16 |
17 | This can lead to faster development times, better team collaboration, and a more flexible and scalable final product.
18 |
19 | Thus we have a set of puzzles that still need to be able to “assemble”. More details are below.
20 |
21 | #### Assemble correctly from Childhood!
22 |
23 | > FSD strives to be perfect. It was born with Mission — create a Сontrollable Unidirectional Encapsulated Flow (explicit one-way links).
24 |
25 | I imagine a stream that turns into an ocean. A small stream knows nothing about the ocean, but the ocean knows about all the streams, rivers, lakes, and seas that feed it.
26 |
27 | > Let’s say more — one river does not know about the existence of the other. This is the prerogative of the seas and oceans.
28 |
29 | Technically, It means that the Bottom Layer (for example, shared) knows nothing about all the layers above or next to it. Upper layers (ex. entities) can use all the layers below, like a river that flows into the sea, not vice versa.
30 |
31 | 
32 |
33 | Let’s remember these Scope Rules. This is a small price for the flexibility and adaptivity that it gives.
34 |
35 | ## Structure example
36 |
37 | - src/
38 |
39 | - app
40 | - app-router.tsx
41 | - app-store
42 | - processes/ `# (Optional) Application processes running over pages`
43 | - pages/ `# Application pages`
44 |
45 | - not-found
46 | - task-details
47 |
48 | - widgets/ `# (optional) Independent and self-contained blocks for pages`
49 | - features/ `# Processing of user scenarios`
50 |
51 | - tasks-filter
52 | - toggle-task
53 |
54 | - entities/ `# (Optional) Business entities that domain logic operates`
55 | - task
56 | - task-card
57 | - task-row
58 | - shared/ `# Reused modules, non-business specific`
59 | - api/ `# getTasksList api is here`
60 | - lib/ `# routerSelectors`
61 | - ui/ `# ui-kit modules`
62 |
63 | > `app/`: Contains a setup of routing, store, and global styles.
64 | > `processes/`: (Optional) Application processes running over pages
65 | > `pages/`: Contains the route components for each page in the app, mostly composition, hardly any logic.
66 | > `widgets/`: Contains the “assembled” post card, with content and interactive buttons that are wired up to the relevant calls on the back-end.
67 | > `features/`: Always contains the interactivity of the card and the logic of processing those interactions.
68 | > `entities/`: Сontains the skeleton of the card with slots for content and the interactive elements.
69 | > `shared/`: Reusable functionality, detached from the specifics of the project/business.(e.g. UIKit, libs, API)
70 |
--------------------------------------------------------------------------------
/architecture-approaches/modular.md:
--------------------------------------------------------------------------------
1 | # Modular
2 |
3 | 1. [General information](#general-information)
4 | 2. [Structure example](#structure-example)
5 |
6 | ## General information
7 |
8 | Module architecture, also known as modular architecture, is an approach to software design and development that emphasizes the use of small, self-contained, and reusable modules. In this context, a module is a discrete unit of functionality or code that performs a specific task or provides a particular feature. Each module is designed to be independent and can be easily combined with other modules to build complex systems.
9 |
10 | The main objectives of module architecture are:
11 |
12 | 1. **Modularity**: The system is broken down into smaller, manageable pieces (modules), each responsible for a specific functionality. This makes the codebase easier to understand, test, and maintain.
13 |
14 | 2. **Reusability**: Modules are designed to be reusable, meaning they can be utilized in multiple parts of the application or even in different projects. This reduces redundant code and development time.
15 |
16 | 3. **Encapsulation**: Modules hide their internal implementation details and expose only the necessary interfaces or APIs. This ensures that other parts of the application can interact with a module without needing to know how it works internally.
17 |
18 | 4. **Scalability**: As the application grows, new modules can be added or existing ones modified without affecting the entire codebase. This facilitates the ability to scale the application in a more manageable way.
19 |
20 | 5. **Dependency Management**: Modules often have well-defined dependencies, which makes it easier to manage and update dependencies within the application.
21 |
22 | 6. **Code Organization**: With module architecture, the codebase is organized into a structured hierarchy, making it easier for developers to navigate and locate specific functionalities.
23 |
24 | Module architecture is commonly used in various programming paradigms, including object-oriented programming, functional programming, and component-based architectures (e.g., React and Angular). In these paradigms, modules are typically represented as classes, functions, components, or packages, depending on the programming language or framework.
25 |
26 | Many modern programming languages and frameworks provide features to support modular architecture, such as package managers (e.g., npm for JavaScript), import/export statements, and dependency injection.
27 |
28 | Overall, module architecture fosters maintainable, scalable, and reusable codebases, making it a favored approach in software development for building robust and efficient systems.
29 |
30 | ## Structure example
31 |
32 | - src/
33 |
34 | - modules/
35 |
36 | - user/
37 | - UserList.tsx
38 | - UserDetail.tsx
39 | - products/
40 | - ProductList.tsx
41 | - ProductDetail.tsx
42 |
43 | - components/
44 |
45 | - header/
46 | - Header.tsx
47 | - footer/
48 | - Footer.tsx
49 |
50 | - services/
51 |
52 | - api.ts
53 | - auth.ts
54 | - validation.ts
55 |
56 | - redux/
57 |
58 | - actions/
59 | - actionTypes.ts
60 | - userActions.ts
61 | - productActions.ts
62 | - reducers/
63 | - userReducer.ts
64 | - productReducer.ts
65 | - store.ts
66 |
67 | - assets/
68 |
69 | - images/
70 | - logo.png
71 | - background.jpg
72 | - icons/
73 | - menu.svg
74 | - close.svg
75 |
76 | - App.tsx
77 |
--------------------------------------------------------------------------------
/architecture-approaches/module-federation.md:
--------------------------------------------------------------------------------
1 | # Module federation
2 |
3 | 1. [General information](#general-information)
4 | 2. [When do we need use?](#when-do-we-need-use)
5 | 3. [Get started](#get-started)
6 |
7 | ## General information
8 |
9 | Module Federation is a feature introduced in Webpack 5 that allows you to share JavaScript modules (chunks) across multiple applications at runtime. It enables developers to create a federated architecture, where different applications can dynamically consume and use each other's code as if they were part of the same application.
10 |
11 | The main advantages of Module Federation include:
12 |
13 | 1. **Code Sharing**: Module Federation allows you to share code between applications, reducing duplication and leading to smaller bundle sizes for each application.
14 |
15 | 2. **Micro Frontends**: With Module Federation, you can build micro frontends, where different teams can work independently on separate applications and still collaborate and share code efficiently.
16 |
17 | 3. **Decoupled Architecture**: Each application can be decoupled and developed independently, providing more flexibility and scalability in the overall architecture.
18 |
19 | 4. **Dynamic Loading**: Applications can dynamically load modules from other applications at runtime, enabling a more efficient and optimized user experience.
20 |
21 | 5. **Shared State**: Module Federation allows shared state management between applications, making it easier to share data and communicate between different parts of the application.
22 |
23 | The basic workflow of using Module Federation involves:
24 |
25 | 1. **Creating the Host Application**: This is the main application that will consume modules from other applications. It defines the remotes (external applications) it wants to consume.
26 |
27 | 2. **Creating the Remote Applications**: These are the applications that will provide modules to the host application. Each remote application exposes certain modules for consumption by the host.
28 |
29 | 3. **Configuration**: The host application and remote applications need to be configured properly to allow sharing of modules. This involves specifying which modules to share and how to load them.
30 |
31 | 4. **Runtime Sharing**: At runtime, the host application dynamically loads and consumes modules from the remote applications.
32 |
33 | Module Federation is a powerful feature that opens up new possibilities for building complex, modular, and scalable web applications. It allows developers to create a more efficient development workflow by breaking down monolithic applications into smaller, more manageable parts that can be independently developed and deployed.
34 |
35 | ## When do we need use?
36 |
37 | Module Federation is particularly useful in the following cases:
38 |
39 | 1. **Micro Frontends**: When building large-scale applications with multiple teams and features, Module Federation enables you to adopt a micro frontend architecture. Different teams can develop and maintain separate applications (micro frontends) independently, and these micro frontends can then be combined to create the complete application.
40 |
41 | 2. **Decentralized Development**: If you have multiple development teams working on different parts of a single application, Module Federation allows each team to maintain their own codebase and independently deploy changes. This can lead to faster development cycles and better team autonomy.
42 |
43 | 3. **Shared Components and Libraries**: Module Federation is beneficial when you have shared components, libraries, or utility modules that are used across multiple applications. Instead of duplicating these modules in each application, you can centralize them in one location and share them using Module Federation.
44 |
45 | 4. **Dynamic Loading**: When you want to optimize loading times and improve performance by dynamically loading chunks of code only when needed, Module Federation is a powerful tool. It allows applications to fetch and load modules on-demand, reducing initial load times and keeping the main bundle size smaller.
46 |
47 | 5. **Scaling Applications**: Module Federation can help you scale your application by enabling the decomposition of a monolithic codebase into smaller, more manageable modules. This can lead to better maintainability, faster build times, and improved development velocity.
48 |
49 | 6. **Legacy Code Integration**: If you have an existing application that you want to modernize, Module Federation allows you to gradually introduce new features and technologies without rewriting the entire application. You can build new functionalities as separate micro frontends and integrate them into the existing application.
50 |
51 | 7. **Shared State Management**: Module Federation can facilitate shared state management across applications. If you have multiple applications that need to share data or communicate with each other, Module Federation provides a way to achieve that without resorting to complex communication mechanisms.
52 |
53 | In summary, Module Federation is valuable in scenarios where you want to create a modular, decoupled, and scalable architecture, with the ability to dynamically share and load modules across different parts of your application ecosystem. It allows for efficient collaboration among development teams, improves code sharing and reuse, and promotes a more flexible and maintainable codebase.
54 |
55 | ## Get started
56 |
57 | To get started with Module Federation, you'll need to follow these general steps:
58 |
59 | 1. **Update Webpack to Version 5**: Module Federation is a feature introduced in Webpack 5, so make sure you have Webpack 5 or a later version installed in your project.
60 |
61 | 2. **Create the Host Application**: Decide which application will be the host that consumes modules from other applications. This will be the main application that imports and uses remote modules.
62 |
63 | 3. **Create the Remote Applications**: Identify the applications that will provide modules (remote modules) to the host application. These are the applications whose code you want to share and consume dynamically.
64 |
65 | 4. **Set up Webpack Configurations**:
66 |
67 | a. In the host application, configure the webpack.config.js file to use the Module Federation plugin. Define the remotes (external applications) from which you want to consume modules.
68 |
69 | b. In the remote applications, also configure the webpack.config.js file to use the Module Federation plugin. Define the exposed modules that the host application can consume.
70 |
71 | 6. **Build the Applications**: Build each application using their respective webpack configurations.
72 |
73 | 7. **Host Application Integration**: In the host application, you can dynamically load remote modules using SystemJS or Webpack 5's native dynamic import() function. Use the import statement to load the remote modules as needed in your host application components.
74 |
75 | 8. **Run the Applications**: Deploy or serve your applications. Ensure that all applications are accessible and running.
76 |
77 | 9. **Verify Functionality**: Test your applications to ensure that modules are being shared and consumed correctly. Check that the host application can load and use remote modules from the remote applications.
78 |
79 | Here's a high-level code example to illustrate how you can integrate Module Federation into your host application:
80 |
81 | ```javascript
82 | // webpack.config.js (Host Application)
83 | const { ModuleFederationPlugin } = require("webpack");
84 |
85 | module.exports = {
86 | // ...other configurations...
87 |
88 | plugins: [
89 | new ModuleFederationPlugin({
90 | name: "host_app",
91 | remotes: {
92 | remote_app: "remote_app@http://localhost:3001/remoteEntry.js", // URL of the remote application's entry file
93 | },
94 | }),
95 | ],
96 | };
97 |
98 | // app.js (Host Application)
99 | import("remote_app/Module").then((remoteModule) => {
100 | // Use the remote module in your host application
101 | });
102 | ```
103 |
104 | With this setup, the host application can consume the `Module` exported by the `remote_app`. The `remote_app` is another application (a remote) that exposes the `Module` for consumption.
105 |
106 | The steps may vary based on your specific project setup and requirements, but these general guidelines should help you get started with Module Federation. Be sure to refer to the official Webpack documentation and relevant tutorials for more in-depth guidance.
107 |
--------------------------------------------------------------------------------
/data-fetching/axios.md:
--------------------------------------------------------------------------------
1 | # Axios
2 |
3 | * [General information](#general-information)
4 | * [Pros and cons](#pros-and-cons)
5 | * [Configuration](#configuration)
6 |
7 | ## General information
8 |
9 | Axios is a promise-based HTTP Client for node.js and the browser. It is isomorphic (= it can run in the browser and nodejs with the same codebase). On the server-side it uses the native node.js http module, while on the client (browser) it uses XMLHttpRequests.
10 |
11 | The official documentation you can find [here](https://axios-http.com/docs/intro).
12 |
13 | ---
14 |
15 | ## Pros and cons
16 |
17 | Pros:
18 |
19 | 1. **Simplicity**: Axios provides a simple and straightforward API, making it easy to use and understand. It abstracts away the complexities of making HTTP requests, handling responses, and managing errors.
20 |
21 | 2. **Flexibility**: Axios can be used in various environments, including web browsers, React Native, and Node.js. It supports different platforms and provides consistent functionality across them.
22 |
23 | 3. **Promise-based**: Axios uses promises, which allows you to handle asynchronous operations in a more elegant and readable way. Promises enable chaining of operations, error handling, and better control flow.
24 |
25 | 4. **Request and response interception**: Axios allows you to intercept and modify requests and responses through the use of interceptors. This feature is helpful for adding custom headers, handling authentication, and performing other tasks before the request is sent or after the response is received.
26 |
27 | 5. **Automatic request and response transformation**: Axios can automatically transform request and response data. For example, it can parse JSON responses into JavaScript objects or convert request payloads into different formats like JSON, FormData, or URL-encoded data.
28 |
29 | 6. **Testing**: It's easy to mock, there are a lot of libraries to mock and use mocks with the tests
30 |
31 | Cons:
32 |
33 | 1. **Size**: Axios is a relatively small library, but it does add some overhead to your project's size. If you're working on a performance-sensitive application where minimizing bundle size is crucial, you may consider using a smaller HTTP library or writing custom code instead.
34 |
35 | 2. **Additional dependency**: Axios is an external dependency that needs to be included in your project. If you're already using another HTTP library or have a minimalistic approach, adding Axios may not be necessary and can increase the complexity of your project.
36 |
37 | 3. **Limited browser support for server-side features**: Some advanced features, such as canceling requests or setting custom headers in cross-origin requests, may have limitations or require server-side support. It's important to be aware of these constraints when using Axios in a browser environment.
38 |
39 | ---
40 |
41 | ## Configuration
42 |
43 | Inside your React project directory, run the following:
44 |
45 | ```plaintext
46 | pnpm add axios
47 | ```
48 |
49 | ### Creating an instance
50 |
51 | You can create a new instance of axios with a custom config.
52 |
53 | ```typescript
54 | import axios from 'axios';
55 |
56 | export const Axios = axios.create({
57 | baseURL: `${import.meta.env.VITE_API_URL}`,
58 | });
59 |
60 | Axios.defaults.headers.common['Content-Type'] = 'application/json';
61 |
62 | Axios.interceptors.request.use(
63 | (config) =>
64 | new Promise((resolve) => {
65 | // handling access/refresh tokens logic
66 | resolve(config);
67 | })
68 | );
69 |
70 | Axios.interceptors.response.use(
71 | (response) => response,
72 | (error) => {
73 | if (error.response.status === 401) {
74 | // sign out current user
75 | }
76 |
77 | // Error parsing logic
78 |
79 | return Promise.reject(error);
80 | }
81 | );
82 |
83 | ```
84 |
--------------------------------------------------------------------------------
/data-fetching/react-query.md:
--------------------------------------------------------------------------------
1 | # React Query (Tanstack Query)
2 |
3 | * [General information](#general-information)
4 | * [Pros and cons](#pros-and-cons)
5 | * [Getting started](#getting-started)
6 | * [Cache](#cache)
7 |
8 | ## General information
9 |
10 | React Query is a popular JavaScript library used for managing, caching, and synchronizing remote data in React applications. It provides a simple and declarative way to fetch, cache, and update data from various data sources, such as APIs, GraphQL endpoints, or local storage.
11 |
12 | The official documentation you can find [here](https://tanstack.com/query/latest/docs/react/overview).
13 |
14 | Here are some key features and concepts of React Query:
15 |
16 | 1. Query: A query represents a request for data from a remote data source. It can fetch data from an API endpoint and handle caching, background refetching, and invalidation. React Query provides hooks like useQuery to initiate and manage queries.
17 |
18 | 2. Mutation: A mutation is used for modifying data on the server. It allows you to perform operations like creating, updating, or deleting data. React Query provides hooks like useMutation to handle mutations and manage the result states.
19 |
20 | 3. Query Invalidation and Refetching: React Query automatically manages the caching of data and provides mechanisms for invalidating and refetching queries. You can manually trigger a refetch or let React Query handle it based on various options like stale time, polling intervals, or events.
21 |
22 | 4. Query States and Data Management: React Query maintains various states for a query, such as loading, error, data, and more. These states help you handle different scenarios and render UI accordingly. React Query also provides helper functions and utilities to transform, filter, or combine data.
23 |
24 | 5. Optimistic Updates: React Query supports optimistic updates, allowing you to immediately update the UI with the expected result of a mutation before the actual response from the server. This enhances the perceived performance of your application.
25 |
26 | 6. Integration with React Components: React Query is designed to seamlessly integrate with React components. It provides a QueryClientProvider component to wrap your application and a set of hooks to fetch and manage data within your components.
27 |
28 | 7. Devtools and Debugging: React Query offers a browser extension called React Query Devtools, which provides a UI for inspecting and debugging your queries, mutations, and cache. It helps you visualize and understand the state of your data fetching processes.
29 |
30 | 8. React Query is known for its simplicity, powerful features, and excellent developer experience. It simplifies complex data fetching scenarios, improves performance, and reduces boilerplate code in React applications.
31 |
32 | ---
33 |
34 | ## Pros and cons
35 |
36 | Pros:
37 |
38 | 1. Simplified Data Fetching: React Query provides a simple and declarative approach to fetching and managing data. It abstracts away the complexity of handling asynchronous data fetching, caching, and synchronization, making it easier to work with remote data sources.
39 |
40 | 2. Caching and State Management: React Query includes a built-in caching mechanism that eliminates the need for manual data caching. It intelligently manages data updates, background refetching, and cache invalidation, resulting in improved performance and reduced network requests.
41 |
42 | 3. Optimistic Updates: The library supports optimistic updates, allowing you to update the UI immediately with the expected result of a mutation, providing a more responsive user experience. It handles the synchronization with the server in the background.
43 |
44 | 4. Seamless Integration with React: React Query seamlessly integrates with React components and follows the React Hooks pattern. It provides a set of hooks that can be easily used within functional components, making it intuitive and familiar to React developers.
45 |
46 | 5. Developer-Friendly Features: React Query offers various developer-friendly features, such as query retries, query deduplication, query invalidation, and result transformations. It also provides a devtools extension that aids in debugging and inspecting queries and cache states.
47 |
48 | 6. Extensibility: React Query is designed to be extensible, allowing you to customize its behavior and integrate with other libraries or data sources. You can create custom hooks, modify query configurations, or add plugins to extend its capabilities.
49 |
50 | Cons:
51 |
52 | 1. Learning Curve: While React Query simplifies many aspects of data fetching, it still requires some initial learning and understanding of its concepts and API. It may take some time for developers who are new to the library to become proficient in using it effectively.
53 |
54 | 2. Overhead for Simple Use Cases: React Query provides a robust set of features, but for simple use cases where basic data fetching is required, it might introduce unnecessary complexity. In such scenarios, using a lighter solution like fetch or axios directly could be more straightforward.
55 |
56 | 3. GraphQL Limitations: Although React Query can work with GraphQL APIs, it doesn't provide specific optimizations for GraphQL queries. For advanced GraphQL use cases, specialized GraphQL libraries like Apollo Client might be a better fit.
57 |
58 | ## Getting Started
59 |
60 | Inside your React project directory, run the following:
61 |
62 | ```plaintext
63 | pnpm add @tanstack/react-query
64 | ```
65 |
66 | This code snippet very briefly illustrates the 3 core concepts of React Query:
67 |
68 | ```typescript
69 | import {
70 | useQuery,
71 | useMutation,
72 | useQueryClient,
73 | QueryClient,
74 | QueryClientProvider,
75 | } from '@tanstack/react-query'
76 | import { getTodos, postTodo } from '../my-api'
77 |
78 | // Create a client
79 | const queryClient = new QueryClient()
80 |
81 | function App() {
82 | return (
83 | // Provide the client to your App
84 |
85 |
86 |
87 | )
88 | }
89 |
90 | function Todos() {
91 | // Access the client
92 | const queryClient = useQueryClient()
93 |
94 | // Queries
95 | const query = useQuery({ queryKey: ['todos'], queryFn: getTodos })
96 |
97 | // Mutations
98 | const mutation = useMutation({
99 | mutationFn: postTodo,
100 | onSuccess: () => {
101 | // Invalidate and refetch
102 | queryClient.invalidateQueries({ queryKey: ['todos'] })
103 | },
104 | })
105 |
106 | return (
107 |
108 |
109 | {query.data?.map((todo) => (
110 |
{todo.title}
111 | ))}
112 |
113 |
114 |
124 |
125 | )
126 | }
127 |
128 | render(, document.getElementById('root'))
129 | ```
130 |
131 | ---
132 |
133 | ## Cache
134 |
135 | Working with cache in React Query is straightforward and intuitive. React Query automatically manages the cache for you, but also provides flexibility to customize and interact with the cache when needed. Here's how you can work with the cache in React Query:
136 |
137 | 1. Configuring the Query Client:
138 | Start by creating a Query Client using the `QueryClient` class from React Query. You can configure the cache options when creating the client instance:
139 |
140 | ```javascript
141 | import { QueryClient, QueryClientProvider } from 'react-query';
142 |
143 | const queryClient = new QueryClient({
144 | defaultOptions: {
145 | queries: {
146 | cacheTime: 30000, // Time in milliseconds to keep data in the cache
147 | staleTime: 10000, // Time in milliseconds before considering data stale
148 | },
149 | },
150 | });
151 |
152 | function App() {
153 | return (
154 |
155 | {/* Your app components */}
156 |
157 | );
158 | }
159 |
160 | ```
161 |
162 | 2. Fetching Data with Caching:
163 | Use the `useQuery` hook to fetch data and automatically cache the results. React Query will handle caching, background refetching, and cache invalidation based on the configured options. Here's an example:
164 |
165 | ```javascript
166 | import { useQuery } from 'react-query';
167 |
168 | function ExampleComponent() {
169 | const { data, isLoading, isError } = useQuery('todos', fetchTodos);
170 |
171 | if (isLoading) {
172 | return
Loading...
;
173 | }
174 |
175 | if (isError) {
176 | return
Error fetching data
;
177 | }
178 |
179 | return (
180 |
181 | {data.map((todo) => (
182 |
{todo.title}
183 | ))}
184 |
185 | );
186 | }
187 |
188 | ```
189 |
190 | 3. Manually Invalidating and Refetching:
191 | React Query provides methods to manually invalidate and refetch data. You can use the `invalidateQueries` function to invalidate one or more queries in the cache and trigger a refetch:
192 |
193 | ```javascript
194 | import { useMutation, queryClient } from 'react-query';
195 |
196 | function ExampleComponent() {
197 | const deleteTodo = useMutation(deleteTodoAPI, {
198 | onSuccess: () => {
199 | queryClient.invalidateQueries('todos');
200 | },
201 | });
202 |
203 | return (
204 |
207 | );
208 | }
209 | ```
210 |
--------------------------------------------------------------------------------
/forms/storing-in-local-storage.md:
--------------------------------------------------------------------------------
1 | # Storing form data in localStorage
2 |
3 | 1. [General](#general)
4 | 2. [useLocalStorage hook](#uselocastorage-hook)
5 | - [How to use with react-hook-form](#how-to-use-with-react-hook-form)
6 | - [How to use with Formik](#how-to-use-with-formik)
7 |
8 | ## General
9 |
10 | Storing form data in `localStorage` can be useful for scenarios where you want to persist form data even if the user refreshes the page or navigates away and returns later. It allows you to retain the form state between sessions.
11 |
12 | ## useLocalStorage hook
13 |
14 | The `useLocalStorage` hook, which enables you to store and retrieve data in/from localStorage with ease.
15 |
16 | ```ts
17 | import { useCallback, useState } from "react";
18 |
19 | export const useLocalStorage = (key: string, initialValue: T) => {
20 | // The useState hook manages the state for the stored value
21 | const [storedValue, setStoredValue] = useState(() => {
22 | // On the initial render, retrieve the value from localStorage if available, or use the initial value provided
23 | try {
24 | const item = localStorage.getItem(key);
25 | return item ? JSON.parse(item) : initialValue;
26 | } catch (error) {
27 | console.log(error);
28 | return initialValue;
29 | }
30 | });
31 |
32 | // useCallback is used to memoize the function, preventing unnecessary re-renders
33 | const setValue = useCallback(
34 | (value: T) => {
35 | try {
36 | // Set the storedValue state and update the value in localStorage
37 | setStoredValue((prev) => {
38 | const valueToStore = value instanceof Function ? value(prev) : value;
39 | localStorage.setItem(key, JSON.stringify(valueToStore));
40 | return valueToStore;
41 | });
42 | } catch (error) {
43 | console.log(error);
44 | }
45 | },
46 | [key]
47 | );
48 |
49 | const clear = useCallback(() => {
50 | // Remove the value from localStorage
51 | localStorage.removeItem(key);
52 | }, [key]);
53 |
54 | const getValue = useCallback(() => {
55 | // Get the value from localStorage or use the initial value provided
56 | try {
57 | const item = localStorage.getItem(key);
58 | return item ? JSON.parse(item) : initialValue;
59 | } catch (error) {
60 | console.log(error);
61 | return initialValue;
62 | }
63 | }, [initialValue, key]);
64 |
65 | // Return the storedValue state and the utility functions to manage the stored value
66 | return { value: storedValue, setValue, clear, getValue };
67 | };
68 | ```
69 |
70 | ### How to use with react-hook-form
71 |
72 | ```ts
73 | import { FC, useEffect } from "react";
74 | import { useForm } from "react-hook-form";
75 | import { useLocalStorage } from "./useLocalStorage";
76 | import { ControlledTextField } from "./ControlledTextField";
77 |
78 | interface FormValues {
79 | name: string;
80 | email: string;
81 | }
82 |
83 | // define initial form values
84 | const initialValues: FormValues = {
85 | name: "",
86 | email: "",
87 | };
88 |
89 | const FormComponent: FC = () => {
90 | const {
91 | value: storedFields,
92 | setValue: setStoredFields,
93 | clear,
94 | } = useLocalStorage("formData", initialValues); // set localStorage "key" and "initialValues"
95 |
96 | const {
97 | register,
98 | handleSubmit,
99 | formState: { errors, isSubmitSuccessful },
100 | } = useForm({
101 | defaultValues: storedFields,
102 | });
103 |
104 | const formValues = watch();
105 |
106 | const onSubmit = (data: FormValues) => {
107 | console.log(data); // Data contains the form input values
108 | setStoredFields(data); // Set form values to local storage after submit
109 | };
110 |
111 | useEffect(() => {
112 | // Set form values to local storage in every onChange values (optional)
113 | setStoredFields(formValues);
114 | }, [formValues, setStoredFields]);
115 |
116 | return (
117 |
132 | );
133 | };
134 |
135 | export default FormComponent;
136 | ```
137 |
138 | ### How to use with Formik
139 |
140 | ```ts
141 | import { FC, useEffect } from "react";
142 | import { Field, useFormik } from "formik";
143 | import { Button } from "@mui/material";
144 | import CustomTextField from "./CustomTextField";
145 |
146 | interface MyFormValues {
147 | name: string;
148 | email: string;
149 | }
150 |
151 | const initialValues: MyFormValues = {
152 | name: "",
153 | email: "",
154 | };
155 |
156 | const MyForm: FC = () => {
157 | const {
158 | value: storedFields,
159 | setValue: setStoredFields,
160 | clear,
161 | } = useLocalStorage("formData", initialValues); // set localStorage "key" and "initialValues"
162 |
163 | const formik = useFormik({
164 | initialValues: storedFields, // pass values from useLocalStorage as initialValues
165 | onSubmit: (values) => {
166 | // Handle form submission logic here
167 | console.log(values);
168 | setStoredFields(values); // Set form values to local storage after submit
169 | },
170 | });
171 |
172 | useEffect(() => {
173 | // Set formik.values to local storage in every onChange values (optional)
174 | setStoredFields(formik.values);
175 | }, [setStoredFields, formik.values]);
176 |
177 | return (
178 |
185 | );
186 | };
187 |
188 | export default MyForm;
189 | ```
190 |
--------------------------------------------------------------------------------
/git/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # Pull Request Template Documentation
2 |
3 | A pull request template is a standardized document used to guide contributors in creating pull requests with consistent and relevant information. It helps streamline the review process and ensures that essential details are provided for the reviewer to understand the purpose and changes introduced in the pull request. In this documentation, we'll cover how to create a pull request template for your project.
4 |
5 | ## Step 1: Define the Template Sections
6 |
7 | Decide on the sections you want to include in your pull request template. Typical sections may include:
8 |
9 | 1. **Title**: A clear and concise title summarizing the purpose of the pull request.
10 | 2. **Description**: A detailed description of the changes made in the pull request.
11 | 3. **Motivation**: The reason behind the changes and why they are necessary.
12 | 4. **Testing**: Instructions on how to test the changes and any test results.
13 | 5. **Screenshots/GIFs**: Visual aids to showcase the changes (if applicable).
14 | 6. **Related Issues**: Mention any related issues or pull requests.
15 | 7. **Checklist**: A checklist of tasks that the contributor should complete before submitting the pull request.
16 |
17 | ## Step 2: Create the Template File
18 |
19 | Open your text editor and create a new file with the filename `pull_request_template.md`. You can place this file in the root directory of your project or in a `.github` folder.
20 |
21 | ## Step 3: Write the Template Content
22 |
23 | Using the sections defined in Step 1, write the content for each section in the template file. Here's an example of a pull request template in Markdown format:
24 |
25 | ```markdown
26 | ## Pull Request Title
27 |
28 | [Provide a clear and concise title for your pull request]
29 |
30 | ## Description
31 |
32 | [Explain the changes introduced by the pull request in detail]
33 |
34 | ## Motivation
35 |
36 | [Explain the reason behind these changes and why they are necessary]
37 |
38 | ## Testing
39 |
40 | [Describe how the changes were tested and provide test results]
41 |
42 | ## Screenshots/GIFs
43 |
44 | [Include any relevant screenshots or GIFs showcasing the changes (if applicable)]
45 |
46 | ## Related Issues
47 |
48 | [Cite any related issues or pull requests that are associated with this pull request]
49 |
50 | ## Checklist
51 |
52 | - [ ] I have tested the changes thoroughly
53 | - [ ] The code follows the project's coding standards
54 | - [ ] Documentation has been updated (if applicable)
55 | - [ ] All tests pass successfully
56 | ```
57 |
58 | ## Step 4: Save and Commit the Template
59 |
60 | Save the changes to your pull request template file and commit it to your project's version control system (e.g., Git). Ensure the template file is in the designated location (root directory or `.github` folder).
61 |
--------------------------------------------------------------------------------
/git/rebase.md:
--------------------------------------------------------------------------------
1 | # Git Rebase Documentation
2 |
3 | ## Table of Contents
4 |
5 | 1. [Introduction](#introduction)
6 | 2. [What is Rebase?](#what-is-rebase)
7 | 3. [When to Use Rebase?](#when-to-use-rebase)
8 | 4. [How to Rebase](#how-to-rebase)
9 | 1. [Interactive Rebase](#interactive-rebase)
10 | 2. [Rebase onto a Different Branch](#rebase-onto-a-different-branch)
11 | 5. [Common Scenarios](#common-scenarios)
12 | 1. [Rebase vs. Merge](#rebase-vs-merge)
13 | 2. [Resolving Conflicts during Rebase](#resolving-conflicts-during-rebase)
14 | 6. [Best Practices](#best-practices)
15 | 7. [Conclusion](#conclusion)
16 |
17 | ## Introduction
18 |
19 | This document provides a guide on how to use `git rebase` – a powerful feature in Git that allows you to modify the commit history of a branch. Rebase can be used to apply changes from one branch onto another, among other purposes.
20 |
21 | ## What is Rebase?
22 |
23 | Rebase is a Git command that allows you to move or combine a sequence of commits to a new base commit. It re-writes the commit history by replaying each commit on top of a different commit or branch. This can lead to a cleaner, linear history, reducing the number of merge commits.
24 |
25 | ## When to Use Rebase?
26 |
27 | Rebase is particularly useful in the following scenarios:
28 |
29 | - Keeping a clean commit history: By rebasing, you can create a linear history without unnecessary merge commits, making it easier to track changes and understand the project's evolution.
30 | - Preparing for pull requests: Before submitting a pull request, you can rebase your branch onto the latest changes from the target branch to avoid potential conflicts.
31 | - Squashing commits: Rebase allows you to combine multiple commits into one, keeping the commit history clean and concise.
32 |
33 | ## How to Rebase
34 |
35 | ### Interactive Rebase
36 |
37 | To perform an interactive rebase, follow these steps:
38 |
39 | 1. **Open the terminal**: Navigate to your repository using the command line.
40 |
41 | 2. **Fetch the latest changes**: Run `git fetch` to get the latest updates from the remote repository.
42 |
43 | 3. **Choose the base commit**: Identify the commit you want to use as the new base. You can use a branch name or a commit hash.
44 |
45 | 4. **Initiate rebase**: Execute the command `git rebase -i `. Or you can use the another way `git rebase -i HEAD~`. For example, if you want to rebase the last 3 commits, you can use `git rebase -i HEAD~3`.
46 |
47 | 5. **Interactive editor**: An interactive editor will open, showing a list of commits that will be included in the rebase. You can choose to re-order, squash, edit, or drop commits. Here the example how it look like
48 | ```
49 | pick 68ed932 [FEC-53]-validation-yup
50 | pick 58824a6 [FEC-53]-add-react-hook-form
51 | pick 2704e35 [FEC-53]-update-hook-form
52 | pick 248c188 [FEC-53]-add-formik
53 | pick 07e292b [FEC-53]-update-formik
54 |
55 | # Rebase 46ed046..ccb84f0 onto 46ed046 (5 commands)
56 | #
57 | # Commands:
58 | # p, pick = use commit
59 | # r, reword = use commit, but edit the commit message
60 | # e, edit = use commit, but stop for amending
61 | # s, squash = use commit, but meld into previous commit
62 | # f, fixup [-C | -c] = like "squash" but keep only the previous
63 | # commit's log message, unless -C is used, in which case
64 | # keep only this commit's message; -c is same as -C but
65 | # opens the editor
66 | # x, exec = run command (the rest of the line) using shell
67 | "~/WorkSpace/fe-cookbook/.git/rebase-merge/git-rebase-todo" 33L, 1465B
68 | ```
69 | 6. **Save and exit**: After making the desired changes, save the file and exit the editor. In command line, you can use `:wq` to save and exit.
70 |
71 | I know that Vim can be challenging to work in for people who are not familiar with it. In this article, we'll cover some fundamental topics like how to exit Vim, rather than quitting Vim.
72 |
73 | I will also include the command that you can use to reveal the corresponding help documentation. To do that, first we need to press ESC a few times, and run the command provided, for example, :h vim-modes, and press Enter.
74 |
75 | ### How to Exit Vim
76 | Press ESC once (sometimes twice)
77 | Make sure you are using the English input method
78 | The next step depends on the current status and your expectations:
79 | If you didn't make any changes, type :q and press Enter/return
80 | If you made some changes and would like to keep them, type :wq and press Enter/return
81 | If you made some changes and would rather discard them, type :q! and press Enter/return
82 | If you want to understand in more detail how this works, let's dive in.
83 |
84 | ### Rebase onto a Different Branch
85 |
86 | To rebase your current branch onto a different branch:
87 |
88 | 1. **Open the terminal**: Navigate to your repository using the command line.
89 |
90 | 2. **Fetch the latest changes**: Run `git fetch` to get the latest updates from the remote repository.
91 |
92 | 3. **Identify the target branch**: Determine the branch you want to rebase onto.
93 |
94 | 4. **Initiate rebase**: Execute the command `git rebase `.
95 |
96 | 5. **Resolve conflicts**: If there are any conflicts, Git will notify you. Resolve the conflicts, stage the changes, and continue the rebase using `git rebase --continue`.
97 |
98 | 6. **Finish the rebase**: Once all conflicts are resolved, the rebase is complete.
99 |
100 | ## Common Scenarios
101 |
102 | ### Rebase vs. Merge
103 |
104 | Both rebase and merge are used to integrate changes from one branch into another, but they achieve different results.
105 |
106 | - **Rebase**: Moves the branch's commits on top of the latest commit in the target branch, creating a linear history. This makes the branch look as if it was started from the latest state of the target branch.
107 |
108 | - **Merge**: Integrates the entire branch's history as a new commit on the target branch. This creates a merge commit, preserving the original branch's commit history.
109 |
110 | ### Resolving Conflicts during Rebase
111 |
112 | During a rebase, if there are conflicting changes between the base and the branch being rebased, Git will pause the process and ask you to resolve the conflicts manually. Once the conflicts are resolved, you can continue the rebase by staging the changes and running `git rebase --continue`.
113 |
114 | ## Best Practices
115 |
116 | - **Backup**: Before performing a rebase, make sure to create a backup or work on a separate branch to avoid losing any important changes.
117 |
118 | - **Keep Rebases Local**: Avoid rebasing branches that have already been pushed to a shared repository. Rebase creates a new commit history, which can cause confusion for other team members.
119 |
120 | ## Conclusion
121 |
122 | Rebasing is a valuable tool for maintaining a clean and organized commit history in Git. It allows you to integrate changes effectively and prepare your branches for merging or pull requests. However, it's essential to use rebase responsibly and understand its impact on the commit history.
123 |
124 | For more details, check out the [official Git documentation](https://git-scm.com/docs/git-rebase). Happy coding!
125 |
--------------------------------------------------------------------------------
/git/squash-merge.md:
--------------------------------------------------------------------------------
1 | # Squash & Merge Documentation for GitHub Pull Requests
2 |
3 | ## Table of Contents
4 |
5 | 1. [Introduction](#introduction)
6 | 2. [What is Squash & Merge?](#what-is-squash--merge)
7 | 3. [When to Use Squash & Merge?](#when-to-use-squash--merge)
8 | 4. [How to Squash & Merge on GitHub](#how-to-squash--merge-on-github)
9 | 5. [How to Squash & Merge in Terminal](#how-to-squash--merge-in-terminal)
10 | 6. [Best Practices](#best-practices)
11 | 7. [Conclusion](#conclusion)
12 |
13 | ## Introduction
14 |
15 | This document provides a guide on how to use the "Squash & Merge" feature in GitHub pull requests. Squash & Merge is a powerful option for integrating changes from a feature branch into the main branch while keeping the commit history clean and concise.
16 |
17 | ## What is Squash & Merge?
18 |
19 | Squash & Merge is a merging strategy offered by GitHub to combine the commits from a feature branch into a single commit before merging them into the target branch (usually the main branch). Instead of keeping the entire commit history, it condenses multiple commits into one, providing a cleaner and more streamlined history.
20 |
21 | ## When to Use Squash & Merge?
22 |
23 | Squash & Merge is particularly useful in the following scenarios:
24 |
25 | - **Maintaining a Clean Commit History**: If the feature branch contains several small, incremental commits that are not essential for the main branch's history, using Squash & Merge helps avoid clutter and keeps the history focused on significant changes.
26 |
27 | - **Pull Request Review Process**: For large features or bug fixes, it is often helpful to create multiple commits during development for better tracking and code review. However, when it comes to merging, squashing those commits can improve the readability of the main branch's history.
28 |
29 | ## How to Squash & Merge on GitHub
30 |
31 | To Squash & Merge a pull request on GitHub, follow these steps:
32 |
33 | 1. **Open the pull request**: Navigate to the pull request page on GitHub.
34 |
35 | 2. **Review the changes**: Ensure that the pull request includes all the necessary changes and has passed any required checks or tests.
36 |
37 | 3. **Initiate the Squash & Merge**: Click on the "Merge" button on the pull request page, then select "Squash and merge" from the dropdown menu.
38 |
39 | 4. **Edit the commit message**: GitHub will present a text box where you can edit the commit message that will be used for the squashed commit. Provide a descriptive and meaningful message that summarizes the changes in the pull request.
40 |
41 | 5. **Squash and confirm**: Once you are satisfied with the commit message, click the "Squash and merge" button to complete the process.
42 |
43 | 6. **Delete the feature branch (optional)**: After the Squash & Merge is successful, you may choose to delete the feature branch to keep the repository tidy.
44 |
45 | ## How to Squash & Merge in Terminal
46 |
47 | To Squash & Merge a pull request using the terminal, follow these steps:
48 |
49 | 1. **Fetch the latest changes**: Ensure your local repository is up to date by running `git fetch` to get the latest updates from the remote repository.
50 |
51 | 2. **Checkout the feature branch**: Switch to the feature branch that you want to squash and merge: `git checkout feature-branch`.
52 |
53 | 3. **Rebase the branch**: Perform an interactive rebase to squash the commits into one. Use the following command: `git rebase -i main`.
54 |
55 | 4. **Squash the commits**: An interactive editor will open, showing a list of commits. Change the word "pick" to "squash" for all the commits except the first one, then save and close the editor.
56 |
57 | 5. **Edit the commit message**: Another editor will open, allowing you to edit the commit message for the squashed commit. Provide a meaningful message and save the file.
58 |
59 | 6. **Complete the rebase**: Finish the rebase by running `git rebase --continue`.
60 |
61 | 7. **Push the changes**: Push the squashed and rebased branch to the remote repository: `git push origin feature-branch`.
62 |
63 | 8. **Create the pull request**: Go to GitHub and create a pull request for the squashed and rebased branch.
64 |
65 | 9. **Merge the pull request**: Follow the steps outlined in the "How to Squash & Merge on GitHub" section to merge the pull request using Squash & Merge.
66 |
67 | ## Best Practices
68 |
69 | - **Clear Commit Messages**: When using Squash & Merge, it's crucial to provide a clear and descriptive commit message that accurately reflects the changes made in the pull request.
70 |
71 | - **Regular Rebasing**: To avoid conflicts during the Squash & Merge process, it's good practice to regularly rebase the feature branch on top of the target branch before creating the pull request.
72 |
73 | - **Discuss with Team**: Before using Squash & Merge, ensure that it aligns with your team's workflow and version control practices. Some teams prefer a different merging strategy.
74 |
75 | ## Conclusion
76 |
77 | Squash & Merge is an effective way to keep your commit history concise and organized, especially when integrating feature branches into the main branch. By following the steps outlined in this guide and adopting best practices, you can make the most of this feature to enhance your Git workflow on GitHub.
78 |
79 | For more details on GitHub's Squash & Merge feature, visit the [GitHub documentation](https://docs.github.com/en/github/collaborating-with-pull-requests/incorporating-changes-into-a-pull-request/squashing-commits). Happy collaborating!
80 |
--------------------------------------------------------------------------------
/images/svg.md:
--------------------------------------------------------------------------------
1 | # Work with SVG icons
2 |
3 | 1. [General](#general)
4 | 2. [Using Vite Plugin for SVGR](#using-vite-plugin-for-svgr)
5 | 3. [Using Webpack Plugin for SVGR](#using-webpack-plugin-for-svgr)
6 | 4. [Using SvgIcon Component from MUI](#using-svgicon-component-from-mui)
7 | 5. [Using SVG as a component](#using-svg-as-a-component)
8 | 6. [Using the Image Tag](#using-the-image-tag)
9 |
10 | ## General
11 |
12 | Using SVG files in your React app is quite straightforward. SVG (Scalable Vector Graphics) is a widely supported image format that's especially useful for web applications due to its ability to scale without losing quality. Here's how you can use SVG files in your React app:
13 |
14 | ## Using the Vite Plugin for SVGR
15 |
16 | [vite-plugin-svgr](https://www.npmjs.com/package/vite-plugin-svgr "vite-plugin-svgr") is a plugin for **Vite** that uses svgr under the hood to transform SVGs into React components.
17 |
18 | You can install it by running the following command:
19 |
20 | ```bash
21 | # with pnpm
22 | pnpm i vite-plugin-svgr
23 |
24 | # with yarn
25 | yarn add vite-plugin-svgr
26 | ```
27 |
28 | Next, add the plugin inside your app's `vite.config.js`:
29 |
30 | ```javascript
31 | import { defineConfig } from "vite";
32 | import react from "@vitejs/plugin-react";
33 | import svgr from "vite-plugin-svgr";
34 |
35 | // https://vitejs.dev/config/
36 | export default defineConfig({
37 | plugins: [svgr(), react()],
38 | });
39 | ```
40 |
41 | Now, you can import the SVG files as React components:
42 |
43 | ```javascript
44 | import { ReactComponent as Logo } from "./logo.svg";
45 | ```
46 |
47 | ## Using Webpack Plugin for SVGR
48 |
49 | [SVGR](https://react-svgr.com/ "SVGR") is a tool that takes raw SVG files and transforms them into React components. It also has a large ecosystem with support for Create React App, Gatsby, Parcel, Rollup, and other technologies.
50 |
51 | Install the package by running the code:
52 |
53 | ```bash
54 | # with pnpm
55 | pnpm install --save-dev @svgr/webpack
56 |
57 | # with yarn
58 | yarn add --dev @svgr/webpack
59 | ```
60 |
61 | Update your `webpack.config.js`:
62 |
63 | ```javascript
64 | module.exports = {
65 | module: {
66 | rules: [
67 | {
68 | test: /\.svg$/i,
69 | issuer: /\.[jt]sx?$/,
70 | use: ["@svgr/webpack"],
71 | },
72 | ],
73 | },
74 | };
75 | ```
76 |
77 | Now, you can import an SVG file as a React component:
78 |
79 | ```javascript
80 | import Logo from "./logo.svg";
81 |
82 | const App = () => {
83 | return (
84 |
85 |
86 |
87 | );
88 | };
89 |
90 | export default App;
91 | ```
92 |
93 | ## Using SvgIcon Component from MUI
94 |
95 | The `SvgIcon` is used to create some custom icons and then display it.
96 |
97 | Here is an example how to use `SvgIcon` in your app if you are using [MUI](https://mui.com/material-ui/getting-started/ "MUI"):
98 |
99 | 1. Create `BaseIcon` component to provide a standardized way to render SVG icons with consistent width, height, and styling using Material-UI's `SvgIcon`.
100 |
101 | ```ts
102 | import { FC } from "react";
103 |
104 | import { SvgIcon, SvgIconProps } from "@mui/material";
105 |
106 | export const BaseIcon: FC = ({
107 | width,
108 | height,
109 | children,
110 | viewBox,
111 | ...props
112 | }) => (
113 |
124 | {children}
125 |
126 | );
127 | ```
128 |
129 | Open up the SVG file in a text editor, and copy-paste the code into a `BaseIcon` component:
130 |
131 | ```ts
132 | import { FC } from "react";
133 |
134 | import { SvgIconProps } from "@mui/material";
135 |
136 | import { BaseIcon } from "../../BaseIcon";
137 |
138 | export const CheckedIcon: FC = ({ ...props }) => (
139 |
140 |
141 |
145 |
146 | );
147 | ```
148 |
149 | Then you can use your Icon in React Components:
150 |
151 | ```javascript
152 | import { CheckedIcon } from "./CheckedIcon";
153 | ```
154 |
155 | ## Using SVG as a component
156 |
157 | We can convert an SVG to a React component by returning it from inside a class or functional component.
158 |
159 | Open up the SVG file in a text editor, and copy-paste the code into a new component:
160 |
161 | ```javascript
162 | export const ArrowUndo = () => {
163 | return (
164 |
178 | );
179 | };
180 | ```
181 |
182 | Now, you can import and render the SVG component in another component like this:
183 |
184 | ```javascript
185 | import { ArrowUndo } from "./path/ArrowUndo.jsx";
186 |
187 | export const Button = () => {
188 | return (
189 |
192 | );
193 | };
194 | ```
195 |
196 | > **Note: that this approach only works with Create React App. CRA uses SVGR under the hood to make it possible to transform and import an SVG as a React component. If you’re not using Create React App, I would recommend using other approaches.**
197 |
198 | ## Using the Image Tag
199 |
200 | If you initialize your app using **CRA** (Create React App), you can import the SVG file in the image source attribute, as it supports it off the bat.
201 |
202 | ```javascript
203 | import YourSvg from "/path/to/image.svg";
204 |
205 | const App = () => {
206 | return (
207 |
208 |
209 |
210 | );
211 | };
212 | export default App;
213 | ```
214 |
215 | > **NOTE: But if you are not using CRA, you have to set up a file loader system in the bundler you're using.**
216 |
217 | Webpack, for instance, has a loader for handling SVGs called [file-loader](https://v4.webpack.js.org/loaders/file-loader/ "file-loader").
218 |
219 | > **NOTE: While this approach is straightforward, it does have one disadvantage: unlike the other methods for importing, you cannot style the SVG imported in a img element. As a result, it will be suitable for an SVG that does not need customization, like logos.**
220 |
--------------------------------------------------------------------------------
/infinite-scroll/infinite-scroll.md:
--------------------------------------------------------------------------------
1 | # Infinite scroll
2 |
3 | 1. [Example with intersection observer](#example-with-intersection-observer)
4 | 2. [Implementation with listening scroll](#implementation-with-listening-scroll)
5 | 3. [NPM alternatives](#npm-alternatives)
6 |
7 | ## Example with intersection observer
8 |
9 | > do not support in old browsers, see the "Can i use" resource
10 |
11 | This component is an Infinite Scroll component in React. It takes the following props: children (the content to be rendered), loading (a boolean indicating whether more data is currently being fetched), and fetchData (a function to fetch additional data).
12 |
13 | When the component mounts, it immediately calls the fetchData function to fetch the initial set of data. The component uses the Intersection Observer API to observe a specific container element (defined by the containerRef ref) as the user scrolls down the page.
14 |
15 | When the observed element (the intersection target) intersects with the viewport by a threshold of 10%, and the loading state is false, the handleIntersection function is triggered. In response, the fetchData function is called again to fetch more data, which is then appended to the existing content.
16 |
17 | The component provides a smooth infinite scroll experience by dynamically loading new content as the user scrolls, leading to a seamless and engaging browsing experience for the user.
18 |
19 | ```ts
20 | import { FC, useState, useEffect, useRef } from "react";
21 |
22 | interface Props {
23 | loading: boolean;
24 | fetchData: () => void;
25 | }
26 |
27 | export const InfiniteScroll: FC = ({ children, loading, fetchData }) => {
28 | const containerRef = useRef(null);
29 |
30 | useEffect(() => {
31 | // Fetch initial data when the component mounts
32 | fetchData();
33 | }, []);
34 |
35 | const handleIntersection: IntersectionObserverCallback = (entries) => {
36 | const entry = entries[0];
37 | if (entry.isIntersecting && !loading) {
38 | fetchData();
39 | }
40 | };
41 |
42 | useEffect(() => {
43 | const options: IntersectionObserverInit = {
44 | root: null,
45 | rootMargin: "0px",
46 | threshold: 0.1, // Set a threshold value to trigger the intersection callback
47 | };
48 |
49 | const observer = new IntersectionObserver(handleIntersection, options);
50 |
51 | if (containerRef.current) {
52 | observer.observe(containerRef.current);
53 | }
54 |
55 | return () => observer.disconnect();
56 | }, [loading]); // Add `loading` to dependency array to avoid re-adding the observer
57 |
58 | return (
59 |
113 | );
114 | };
115 |
116 | export default LanguageSwitcher;
117 | ```
118 |
119 | ## Mock tests
120 |
121 | To mock tests involving **react-intl**, you can use the **react-intl-test-utils** library. It provides helper functions for testing components that use **react-intl**. Here's an example of a test using **react-intl-test-utils**:
122 |
123 | 1\. Install **react-intl-test-utils** before running the tests:
124 |
125 | ```javascript
126 | pnpm install react-intl-test-utils
127 | ```
128 |
129 | 2\. Add tests
130 |
131 | ```javascript
132 | import { render } from '@testing-library/react';
133 | import { IntlProvider } from 'react-intl';
134 | import MyComponent from './MyComponent';
135 |
136 | const messages = {
137 | 'app.greeting': 'Hello!',
138 | };
139 |
140 | test('renders the greeting message', () => {
141 | const { getByText } = render(
142 |
143 |
144 |
145 | );
146 |
147 | const greetingElement = getByText(/Hello!/i);
148 | expect(greetingElement).toBeInTheDocument();
149 | });
150 | ```
--------------------------------------------------------------------------------
/monitoring/sentry.md:
--------------------------------------------------------------------------------
1 | # Sentry
2 |
3 | ## What is it?
4 |
5 | Sentry is an open-source error monitoring and crash reporting tool used by developers and organizations to track and debug software errors and exceptions in real-time. It is designed to help developers identify and fix issues in their applications quickly.
6 |
7 | With Sentry, developers can integrate the tool into their applications and collect data on errors, exceptions, and crashes that occur during runtime. When an error or exception is detected, Sentry captures relevant information such as the stack trace, environment variables, and user context, providing valuable insights into the root cause of the issue.
8 |
9 | The captured data is then aggregated and displayed in the Sentry dashboard, where developers can view and analyze the errors, track their occurrence frequency, and prioritize them based on their impact. Sentry also provides features such as issue assignment, notifications, and release tracking, enabling teams to collaborate and resolve issues efficiently.
10 |
11 | ## How to use Sentry in React applications
12 |
13 | To use Sentry in a React application, you can follow these general steps:
14 |
15 | 1. Check out the official guide of creating a new project in Sentry [admin panel](https://docs.sentry.io/product/sentry-basics/integrate-frontend/create-new-project/).
16 |
17 | 2. Configure [alert rules](https://uptech-team.sentry.io/alerts/rules/) for your project.
18 |
19 | 
20 |
21 | - Click to the "Create alert" button and set conditions for the new alert rule.
22 |
23 | 
24 |
25 | - Create a rule of alerts for non-production environments. Note that here you could configure notifications in Slack channels from your organizations.
26 |
27 | 
28 |
29 | - Create a rule of alerts for the production environment.
30 |
31 | 
32 |
33 | 3. Get the project DSN key:
34 |
35 | 
36 |
37 | 4. Add this key in your ```.env``` file.
38 | 5. Add other Sentry env variables to your ```.env``` file:
39 |
40 | ```js
41 | REACT_APP_SENTRY_DSN=
42 | REACT_APP_SENTRY_AUTH_TOKEN=
43 | REACT_APP_SENTRY_ORG=your-organization-name
44 | REACT_APP_SENTRY_PROJECT=your-project-name
45 | REACT_APP_ENV=local // make this env variable dynamic for different environments
46 | ```
47 |
48 | 6. Check out Sentry configuration [guide](https://docs.sentry.io/platforms/javascript/guides/react/) for React applications.
49 |
50 | 7. Configure Sentry in your ```index.tsx``` file:
51 |
52 | ```typescript
53 | import * as Sentry from "@sentry/react";
54 |
55 | // define your environment names on the project, where Sentry should be enabled
56 | const enabledForEnvironments = ['development', 'staging', 'production'];
57 |
58 | const samplesRateByEnvironment = {
59 | 'development': 1.0,
60 | 'staging': 0.5,
61 | 'production': 0.1
62 | }
63 |
64 | const DEFAULT_TRACING_RATE = 0.1;
65 |
66 | const isSentryEnabled = enabledForEnvironments.includes(ENV);
67 |
68 | const sampleRate = samplesRateByEnvironment[ENV] || DEFAULT_TRACING_RATE;
69 |
70 | Sentry.init({
71 | enabled: isSentryEnabled,
72 | release: process.env.REACT_APP_RELEASE_VERSION, // Configure this variable in your CI to make it dynamic across diffent environments
73 | dsn: process.env.REACT_APP_SENTRY_DSN,
74 | integrations: [Sentry.browserTracingIntegration()],
75 | environment: ENV,
76 | profilesSampleRate: sampleRate,
77 | replaysSessionSampleRate: sampleRate,
78 | tracesSampleRate: sampleRate,
79 | tracePropagationTargets: [
80 | // define targets to which you want propagate Sentry traces (usually API host)
81 | /^https:\/\/api.*\..*domain\.com.*/,
82 | ],
83 | });
84 | ```
85 |
86 | 8. Configure your error boundary component:
87 |
88 | ```typescript
89 | import { Component, ErrorInfo, ReactNode } from "react";
90 | import { withScope, captureException, SeverityLevel } from "@sentry/react";
91 | import { Error } from "@pages";
92 |
93 | interface IProps {
94 | children: ReactNode;
95 | }
96 |
97 | interface IState {
98 | error: null | Error;
99 | }
100 |
101 | export class ErrorBoundary extends Component {
102 | constructor(props: IProps) {
103 | super(props);
104 | this.state = { error: null };
105 |
106 | this.clearState = this.clearState.bind(this);
107 | }
108 |
109 | public componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
110 | this.setState({ error });
111 | withScope((scope) => {
112 | scope.setTag("Custom-Tag", "ErrorBoundary");
113 | scope.setLevel("Error" as SeverityLevel);
114 | Object.keys(errorInfo).forEach((key) => {
115 | scope.setExtra(key, errorInfo[key as keyof ErrorInfo]);
116 | });
117 | captureException(error);
118 | });
119 | }
120 |
121 | public clearState() {
122 | this.setState({ error: null });
123 | }
124 |
125 | public render(): ReactNode {
126 | const { error } = this.state;
127 |
128 | if (error) {
129 | return ;
130 | }
131 | const { children } = this.props;
132 | return children;
133 | }
134 | }
135 | ```
136 |
137 | 9. You can also create a helper function ```reportError``` for catching errors in Sentry:
138 |
139 | ```typescript
140 | interface IReportError {
141 | error: string | Error;
142 | tagKey?: string;
143 | tagValue?: string;
144 | extraInfo?: Extras;
145 | }
146 |
147 | export const reportError = ({
148 | error,
149 | tagKey,
150 | tagValue,
151 | extraInfo,
152 | }: IReportError) => {
153 | withScope((scope) => {
154 | if (tagKey && tagValue) {
155 | scope.setTag(tagKey, tagValue);
156 | }
157 | if (extraInfo) {
158 | scope.setExtras(extraInfo);
159 | }
160 | scope.setLevel("Error" as SeverityLevel);
161 |
162 | captureException(error);
163 | });
164 | };
165 | ```
166 |
167 | 10. After that, you can call it whenever you need in your code:
168 |
169 | - In Axios interceptors:
170 |
171 | ```typescript
172 | Axios.interceptors.response.use(undefined, (error) => {
173 | reportError({
174 | error: `Request failed (${error.response.config.method}/ ${error.response.config.url})`,
175 | extraInfo: error.response.config.data
176 | ? JSON.parse(error.response.config.data)
177 | : {},
178 | });
179 |
180 | const { title, description } = parseServerException(error);
181 | displayToastError(title, description);
182 | return Promise.reject(error);
183 | });
184 | ```
185 |
186 | - In other places in your app:
187 |
188 | ```typescript
189 | try {
190 | await uploadFileToS3(file, uploadURL).then(() =>
191 | setValue(fieldName, imageKey, { shouldDirty: true })
192 | );
193 | } catch {
194 | reportError({ error: "Image file uploading error" });
195 | }
196 | ```
197 |
198 | 11. To enable readable stack traces in your Sentry errors, you need to upload your source maps to Sentry. Check out [guides](https://docs.sentry.io/platforms/javascript/guides/react/sourcemaps/uploading/) of how to upload source maps.
199 |
200 | 12. If you use ```craco``` on your project, feel free to use this config:
201 |
202 | ```typescript
203 | const CracoAlias = require("craco-alias");
204 | const SentryWebpackPlugin = require("@sentry/webpack-plugin");
205 |
206 | module.exports = {
207 | devtool: "source-map",
208 | plugins: [
209 | {
210 | plugin: CracoAlias,
211 | options: {
212 | source: "tsconfig",
213 | baseUrl: ".",
214 | tsConfigPath: "./tsconfig.path.json",
215 | },
216 | },
217 | {
218 | plugin: SentryWebpackPlugin,
219 | options: {
220 | org: process.env.REACT_APP_SENTRY_ORG,
221 | project: process.env.REACT_APP_SENTRY_PROJECT,
222 | include: "build/static/",
223 | urlPrefix: "~/static/",
224 | authToken: process.env.SENTRY_AUTH_TOKEN,
225 | release: process.env.REACT_APP_RELEASE_VERSION,
226 | },
227 | },
228 | ],
229 | };
230 |
231 | export {};
232 | ```
233 |
234 | 13. Here is an example of CI job (CircleCI) for uploading source maps to Sentry:
235 |
236 | ```
237 | notify-sentry-deploy:
238 | executor: app-executor
239 | steps:
240 | - checkout
241 | - attach_workspace:
242 | at: .
243 | - run: |
244 | cat bash.env > $BASH_ENV
245 | - run: |
246 | printenv REACT_APP_RELEASE_VERSION
247 | printenv REACT_APP_ENV
248 | - run:
249 | name: Create release and notify Sentry of deploy
250 | command: |
251 | curl -sL https://sentry.io/get-cli/ | bash
252 | sentry-cli releases -o $REACT_APP_SENTRY_ORG new -p $SENTRY_PROJECT $REACT_APP_RELEASE_VERSION
253 | sentry-cli releases set-commits $REACT_APP_RELEASE_VERSION --auto --ignore-missing
254 | sentry-cli releases files $REACT_APP_RELEASE_VERSION upload-sourcemaps "~/static/"
255 | sentry-cli releases finalize $REACT_APP_RELEASE_VERSION
256 | sentry-cli releases deploys $REACT_APP_RELEASE_VERSION new -e $REACT_APP_ENV
257 | ```
258 |
--------------------------------------------------------------------------------
/notifications/circle-ci-slack.md:
--------------------------------------------------------------------------------
1 | # Slack notifications configuring
2 |
3 | ## Why do we need Slack notifications from CI?
4 |
5 | Here are some of the reasons why we need to use Slack notifications:
6 |
7 | 1. Real-time updates: Slack notifications from CI provide real-time updates on the status of the build process. This allows team members to quickly identify any issues that may arise during the build process and take necessary actions to fix them.
8 | 2. Improved collaboration: By integrating CI notifications with Slack, team members can easily collaborate and communicate with each other. They can share information, provide feedback, and work together to resolve issues in a timely manner.
9 | 3. Increased visibility: Slack notifications from CI provide increased visibility into the build process, allowing team members to track progress and identify bottlenecks. This can help improve the overall efficiency of the development process.
10 | 4. Quick feedback: Slack notifications can provide quick feedback on the success or failure of builds, making it easier to identify and address any issues. This can help prevent bugs and other issues from making it into production.
11 | 5. Customizable alerts: Slack notifications can be customized to meet the specific needs of the development team. For example, notifications can be sent only when specific conditions are met, such as when a build fails or when a specific branch is merged.
12 |
13 | ## How to configure CircleCI notifications in Slack
14 |
15 | 1. Check out the official [tutorial](https://circleci.com/docs/slack-orb-tutorial/) of using the Slack orb to set up Slack notifications in CircleCI.
16 | 2. Instead of suggested in tutorial message template you can use your custom message template. Here are examples of custom templates:
17 |
18 | For failed jobs:
19 |
20 | ```
21 | - slack/notify:
22 | event: fail
23 | template: ""
24 | custom: |
25 | {
26 | "blocks": [
27 | {
28 | "type": "section",
29 | "text": {
30 | "type": "mrkdwn",
31 | "text": "MMT FE ${BUILD_INFO} failed to deploy ❌",
32 | }
33 | },
34 | {
35 | "type": "actions",
36 | "elements": [
37 | {
38 | "type": "button",
39 | "text": {
40 | "type": "plain_text",
41 | "text": "View Job"
42 | },
43 | "url": "${CIRCLE_BUILD_URL}"
44 | }
45 | ]
46 | }
47 | ]
48 | }
49 | channel: "eatable-robot"
50 | ```
51 |
52 | For succeeded jobs:
53 |
54 | ```
55 | - slack/notify:
56 | event: pass
57 | template: ""
58 | custom: |
59 | {
60 | "blocks": [
61 | {
62 | "type": "section",
63 | "text": {
64 | "type": "mrkdwn",
65 | "text": "MMT FE ${BUILD_INFO} has been deployed to *${ENV_NAME}* ✅"
66 | }
67 | },
68 | {
69 | "type": "actions",
70 | "elements": [
71 | {
72 | "type": "button",
73 | "text": {
74 | "type": "plain_text",
75 | "text": "View Job"
76 | },
77 | "url": "${CIRCLE_BUILD_URL}"
78 | }
79 | ]
80 | }
81 | ]
82 | }
83 | channel: "eatable-robot"
84 | ```
85 |
86 | 3. Here is an example of how this message templates look in Slack (successful/failed build deploy):
87 |
88 | 
89 |
--------------------------------------------------------------------------------
/notifications/jira-github.md:
--------------------------------------------------------------------------------
1 | # Integration JIRA tickets with GitHub
2 |
3 | To integrate JIRA tickets with pull requests (PRs) in GitHub, you can use the JIRA and GitHub integration provided by Atlassian. This integration allows you to link JIRA issues with GitHub repositories, and it provides a seamless way to track and manage work across both platforms.
4 |
5 | 1. Enable the JIRA integration in GitHub:
6 |
7 | In your GitHub repository, go to the "Settings" tab and select "Integrations & services" (or "Integrations" in newer versions). Look for the JIRA integration and follow the instructions to enable it. You'll need to provide the URL of your JIRA instance and authorize the integration to access the necessary resources.
8 |
9 | Here is an example of addded JIRA integration to the project:
10 |
11 | 
12 |
13 | Here is an example of how to add JIRA integration to your project from your current organization:
14 |
15 | 
16 |
17 | 2. Link JIRA issue keys to GitHub PRs:
18 | Once the integration is enabled, you can start linking JIRA issues to GitHub PRs. In the body of a PR or a commit message, simply include the JIRA issue key, such as "PROJECT-123." GitHub will recognize the JIRA issue key and automatically link it.
19 |
20 | Here is an example of PR with JIRA FEC-33 ticket number:
21 | 
22 |
23 | 3. View linked JIRA issues:
24 | On the GitHub PR page, you'll be able to see the linked JIRA issues. They may appear in the sidebar or in a separate section, depending on the GitHub UI version. Clicking on a linked issue will take you directly to the corresponding issue in JIRA.
25 |
26 | 4. Automatic status updates:
27 | As you work on the PR and make changes, the JIRA issue linked to the PR will automatically reflect those changes. For example, if the PR is merged, the corresponding JIRA issue may transition to a "Done" status. This synchronization helps keep both platforms updated and aligned.
28 |
29 | 
30 |
31 | 5. Additional features:
32 | The JIRA and GitHub integration offers various additional features, such as the ability to create branches from JIRA issues, view development information in JIRA, and more. Explore the integration settings and documentation to leverage these features.
33 |
34 | Remember that the specific steps and features may vary depending on the versions of JIRA, GitHub, and the integration itself. Make sure to consult the respective documentation for more detailed instructions based on your specific setup.
35 |
--------------------------------------------------------------------------------
/roles-and-permissions/roles-and-permissions.md:
--------------------------------------------------------------------------------
1 | # Roles and permissions
2 |
3 | 1. [General information](#general-information)
4 | 2. [Hook](#hook)
5 | 3. [HOC](#hoc)
6 | 4. [Wrapper component](#wrapper-component)
7 |
8 | ## General information
9 |
10 | Handling roles and permissions in a React app is an essential aspect of building secure and scalable applications, especially when dealing with different user types and access levels. Below are some approaches and best practices to manage roles and permissions effectively in a React app:
11 |
12 | 1. Role-Based Access Control (RBAC):
13 | RBAC is a widely-used approach for managing roles and permissions in applications. In this model, users are assigned specific roles (e.g., admin, manager, user) that determine their access to certain features or functionalities. The application's components and routes can be conditionally rendered based on the user's role.
14 |
15 | 2. Centralized State Management:
16 | Use a centralized state management library like Redux or MobX to manage user roles and permissions globally across the application. This ensures consistency and makes it easier to update roles or permissions when needed.
17 |
18 | 3. Authentication and Authorization:
19 | Implement a robust authentication system to verify user identities and ensure that only authenticated users can access protected parts of the application. Additionally, implement authorization logic to check if the authenticated user has the required permissions for a particular action.
20 |
21 | 4. Route-Based Access Control:
22 | Leverage React Router or similar routing libraries to protect routes based on user roles and permissions. You can create higher-order components (HOCs) or custom route wrappers to control access to specific routes.
23 |
24 | 5. Backend Validation:
25 | While access control can be enforced on the frontend, always ensure that critical operations and sensitive data access are validated on the backend as well. The frontend should act as a visual representation of the backend's access control.
26 |
27 | 6. Secure Data Fetching:
28 | When fetching data from the server, ensure that the backend provides only the data that the user is allowed to access. This prevents unauthorized access to sensitive information.
29 |
30 | 7. Conditional Rendering:
31 | Use conditional rendering techniques to show/hide components or elements based on the user's role and permissions. This helps create a personalized user experience.
32 |
33 | 8. Error Handling:
34 | Implement proper error handling when a user attempts to access restricted areas or perform unauthorized actions. Provide clear feedback to the user and avoid exposing sensitive information in error messages.
35 |
36 | 9. Regular Review and Updates:
37 | Periodically review and update the roles and permissions of users as the application evolves. Users may change roles within an organization, and new features might require updates to access control logic.
38 |
39 | 10. Testing:
40 | Thoroughly test your role-based access control mechanisms to ensure they work as expected. Write unit tests and end-to-end tests to cover various scenarios involving different roles and permissions.
41 |
42 | By following these best practices, you can create a secure and scalable React app with robust role-based access control, providing a smooth and personalized user experience for different user types and access levels.
43 |
44 | ## Hook
45 |
46 | Here's the `usePermissions` hook, assuming you have the user's permissions available in your Redux store:
47 |
48 | ```js
49 | import { useSelector } from "react-redux";
50 |
51 | const usePermissions = () => {
52 | const permissions = useSelector((state) => state.user.permissions);
53 |
54 | const hasPermission = (requiredPermission) => {
55 | return permissions.includes(requiredPermission);
56 | };
57 |
58 | return { permissions, hasPermission };
59 | };
60 |
61 | export default usePermissions;
62 | ```
63 |
64 | ### Usage
65 |
66 | ```js
67 | const MyComponent = () => {
68 | const { hasPermission } = usePermissions();
69 |
70 | // Your component logic here...
71 |
72 | return
{hasPermission("edit_posts") && }
;
73 | };
74 |
75 | export default MyComponent;
76 | ```
77 |
78 | ## HOC
79 |
80 | Here's the implementation of the `withRolesAndPermissions` HOC:
81 |
82 | ```js
83 | const withRolesAndPermissions =
84 | (requiredRoles, requiredPermissions) => (WrappedComponent) => {
85 | const EnhancedComponent = (props) => {
86 | // Replace this with your actual implementation to get user roles and permissions
87 | const userRoles = ["admin", "manager"];
88 | const userPermissions = ["edit_posts"];
89 |
90 | const hasRole = (requiredRole) => userRoles.includes(requiredRole);
91 | const hasPermission = (requiredPermission) =>
92 | userPermissions.includes(requiredPermission);
93 |
94 | const isAuthorized = () => {
95 | if (requiredRoles && requiredRoles.length > 0) {
96 | return requiredRoles.some(hasRole);
97 | }
98 | if (requiredPermissions && requiredPermissions.length > 0) {
99 | return requiredPermissions.every(hasPermission);
100 | }
101 | return true; // No specific roles or permissions required, allow access
102 | };
103 |
104 | return isAuthorized() ? : null;
105 | };
106 |
107 | return EnhancedComponent;
108 | };
109 |
110 | export default withRolesAndPermissions;
111 | ```
112 |
113 | In this HOC, we define a function `withRolesAndPermissions` that takes two arrays: requiredRoles and requiredPermissions. It returns a new function that takes the component to be wrapped (WrappedComponent) and returns an enhanced component (`EnhancedComponent`).
114 |
115 | The `EnhancedComponent` performs the role and permission checks based on the provided requiredRoles and requiredPermissions and renders the WrappedComponent only if the user has the necessary roles and permissions. If the user doesn't meet the requirements, it displays nothing.
116 |
117 | To use this HOC in your components, follow these steps:
118 |
119 | ### Usage
120 |
121 | ```js
122 | const MyComponent = (props) => {
123 | // Your component logic here...
124 |
125 | return (
126 |
127 |
128 |
129 | );
130 | };
131 |
132 | // Specify the required roles and/or permissions when applying the HOC
133 | export default withRolesAndPermissions(
134 | ["admin", "manager"],
135 | ["edit_posts"]
136 | )(MyComponent);
137 | ```
138 |
139 | In this example, we apply the `withRolesAndPermissions` HOC to `MyComponent`, indicating that the user must have either the `admin` or `manager` role and the `edit_posts` permission to access this component. If the user doesn't meet these requirements, the HOC will render nothing instead of the wrapped component.
140 |
141 | By using this composition component, you can easily manage roles and permissions in your React app and control access to different components or features based on the user's role and permissions.
142 |
143 | ## Wrapper component
144 |
145 | Here's the implementation of the `RolesAndPermissionsWrapper` component:
146 |
147 | ```js
148 | const RolesAndPermissionsWrapper = ({
149 | requiredRoles,
150 | requiredPermissions,
151 | children,
152 | }) => {
153 | // Replace this with your actual implementation to get user roles and permissions
154 | const userRoles = ["admin", "manager"];
155 | const userPermissions = ["edit_posts"];
156 |
157 | const hasRole = (requiredRole) => userRoles.includes(requiredRole);
158 | const hasPermission = (requiredPermission) =>
159 | userPermissions.includes(requiredPermission);
160 |
161 | const isAuthorized = () => {
162 | if (requiredRoles && requiredRoles.length > 0) {
163 | return requiredRoles.some(hasRole);
164 | }
165 | if (requiredPermissions && requiredPermissions.length > 0) {
166 | return requiredPermissions.every(hasPermission);
167 | }
168 | return true; // No specific roles or permissions required, allow access
169 | };
170 |
171 | return isAuthorized() ? <>{children}> : null;
172 | };
173 |
174 | export default RolesAndPermissionsWrapper;
175 | ```
176 |
177 | In this Wrapper Component, we receive the `requiredRoles` and `requiredPermissions` as props. We then perform the role and permission checks based on the provided props. If the user has the necessary roles and permissions, the Wrapper Component will render the children. Otherwise, it will display the `null`.
178 | To use this HOC in your components, follow these steps:
179 |
180 | ### Usage
181 |
182 | ```js
183 | const MyComponent = (props) => {
184 | // Your component logic here...
185 |
186 | return (
187 |
188 |
189 |
190 | );
191 | };
192 |
193 | export default () => (
194 |
198 |
199 |
200 | );
201 | ```
202 |
203 | In this example, we wrap `MyComponent` with the `RolesAndPermissionsWrapper` and specify that the user must have either the `admin` or `manager` role and the `edit_posts` permission to access the component. If the user doesn't meet these requirements, the Wrapper Component will render the `null` instead of the wrapped component.
204 |
205 | This approach provides a more declarative way of handling permissions and allows you to specify the requirements directly where you use the component.
206 |
--------------------------------------------------------------------------------
/router/leave-modal.md:
--------------------------------------------------------------------------------
1 | # Leave modal
2 |
3 | 1. [General information](#general-information)
4 | 2. [Hook](#hook)
5 | 3. [Another approach with the useBlocker and useCallbackPrompt hooks](#another-approach-with-the-useblocker-and-usecallbackprompt-hooks)
6 |
7 | ## General information
8 |
9 | The functionality described here involves handling event for a custom prompt modal or using browser-native confirmation dialogs to handle user navigation attempts, such as clicking a link or using the back button, in a React application.
10 |
11 | We need this functionality to ensure that users are aware of potential data loss or unintended actions when attempting to leave a page with unsaved changes. By displaying a prompt or confirmation dialog, we give users the opportunity to confirm their intention to leave the current page or cancel the navigation. This helps prevent accidental data loss and improves the overall user experience by providing clear communication about potential consequences of their actions.
12 |
13 | ## Hook
14 |
15 | ```typescript
16 | import { useEffect } from "react";
17 | import { useBeforeUnload, useLocation, useNavigate } from "react-router-dom";
18 |
19 | interface IProps {
20 | needShowDialog: boolean;
21 | onOpenCustomModal?: () => void;
22 | }
23 |
24 | export const useModalBeforeLeavePage = ({
25 | needShowDialog,
26 | onOpenCustomModal,
27 | }: IProps) => {
28 | const navigate = useNavigate();
29 | const location = useLocation();
30 |
31 | useEffect(() => {
32 | const handleBackButton = (e) => {
33 | if (needShowDialog) {
34 | // prevent back and show modal if needed
35 | e.preventDefault();
36 | onOpenCustomModal();
37 | window.history.pushState(null, null, window.location.pathname);
38 | } else {
39 | // go back
40 | navigate(-1);
41 | }
42 | };
43 |
44 | window.history.pushState(null, null, window.location.pathname);
45 | window.addEventListener("popstate", handleBackButton);
46 |
47 | return () => {
48 | window.removeEventListener("popstate", handleBackButton);
49 | };
50 | }, [location.pathname, needShowDialog, navigate]);
51 |
52 | // show browser default modal when we try to refresh page
53 | useBeforeUnload((e) => {
54 | if (needShowDialog) {
55 | e.preventDefault();
56 | e.returnValue = "";
57 | }
58 | });
59 | };
60 |
61 | // USAGE
62 | const Container = () => {
63 | const [open, setOpen] = useState(false);
64 |
65 | useModalBeforeLeavePage({
66 | needShowDialog: true, // true if data in form
67 | onOpenCustomModal: setOpen(true),
68 | });
69 |
70 | return (
71 |
75 | );
76 | };
77 | ```
78 |
79 | ## Another approach with the useBlocker and useCallbackPrompt hooks
80 |
81 | In the example below we define `useBlocker` and `useCallbackPrompt` hooks:
82 |
83 | ```typescript
84 | // useBlocker.ts hook
85 |
86 | import { useEffect, useContext } from "react";
87 | import { UNSAFE_NavigationContext } from "react-router-dom";
88 |
89 | /* !!! Note that this hook works only with react-router-dom 6.3.0 version and below !!! */
90 |
91 | // Handle the logic of blocking some action in the router prompt
92 | export const useBlocker = (blocker, when = true) => {
93 | const navigator = useContext(UNSAFE_NavigationContext).navigator;
94 |
95 | useEffect(() => {
96 | if (!when) return;
97 |
98 | const unblock = navigator.block((tx) => {
99 | const autoUnblockingTx = {
100 | ...tx,
101 | retry() {
102 | unblock();
103 | tx.retry();
104 | },
105 | };
106 |
107 | blocker(autoUnblockingTx);
108 | });
109 |
110 | return unblock;
111 | }, [navigator, blocker, when]);
112 | };
113 | ```
114 |
115 | ```typescript
116 | // useCallbackPrompt.ts hook
117 |
118 | import { useCallback, useEffect, useState } from "react";
119 | import { useLocation, useNavigate } from "react-router-dom";
120 | import useBlocker from "./useBlocker";
121 |
122 | // Handle the logic of showing the router prompt
123 | export const useCallbackPrompt = (when: boolean): {
124 | showModal: boolean, openModal: () => void, closeModal: () => void, confirm: () => void
125 | } => {
126 | const navigate = useNavigate();
127 | const location = useLocation();
128 |
129 | const [showModal, setShowModal] = useState(false);
130 | const [lastLocation, setLastLocation] = useState(null);
131 | const [confirmedNavigation, setConfirmedNavigation] = useState(false);
132 |
133 | // handle blocking when user click on another route prompt will be shown
134 | const handleBlockedNavigation = useCallback(
135 | (nextLocation) => {
136 | if (
137 | !confirmedNavigation &&
138 | nextLocation.location.pathname !== location.pathname
139 | ) {
140 | setShowModal(true);
141 | setLastLocation(nextLocation);
142 | return false;
143 | }
144 | return true;
145 | },
146 | [confirmedNavigation, location]
147 | );
148 |
149 | const confirm = useCallback(() => {
150 | setShowModal(false);
151 | setConfirmedNavigation(true);
152 | }, []);
153 |
154 | useEffect(() => {
155 | if (confirmedNavigation && lastLocation) {
156 | navigate(lastLocation.location.pathname);
157 | setConfirmedNavigation(false);
158 | }
159 | }, [confirmedNavigation, lastLocation]);
160 |
161 | const openModal = useCallback(() => setShowModal(true), []);
162 | const closeModal = useCallback(() => setShowModal(false), []);
163 |
164 | useBlocker(handleBlockedNavigation, when);
165 |
166 | return { showModal, openModal, closeModal, confirm };
167 | };
168 | ```
169 |
170 | Here is an example of how we can use these hooks in some container component with a custom modal component:
171 |
172 | ```typescript
173 | // USAGE
174 | import { useCallbackPrompt } from "@hooks";
175 | import { LeaveModal } from "@organisms";
176 | import { useCallback, useEffect, ReactNode, FC } from "react";
177 |
178 | interface IProps {
179 | children: ReactNode;
180 | when: boolean;
181 | showByTrigger: boolean;
182 | resetTrigger?: () => void;
183 | handleConfirm?: () => void;
184 | }
185 |
186 | export const LeaveModalContainer: FC = ({
187 | when = false,
188 | showByTrigger = false,
189 | resetTrigger,
190 | handleConfirm,
191 | children,
192 | }) => {
193 | const { showModal, closeModal, openModal, confirm } = useCallbackPrompt(when);
194 |
195 | useEffect(() => {
196 | if (showByTrigger) {
197 | openModal();
198 | }
199 | }, [showByTrigger, resetTrigger]);
200 |
201 | const onHandleClose = useCallback(() => {
202 | closeModal();
203 | if (resetTrigger) {
204 | resetTrigger();
205 | }
206 | }, [resetTrigger]);
207 |
208 | const onHandleConfirm = useCallback(() => {
209 | confirm();
210 | if (resetTrigger) {
211 | resetTrigger();
212 | }
213 | if (handleConfirm) {
214 | handleConfirm();
215 | }
216 | }, [resetTrigger, handleConfirm]);
217 |
218 | return (
219 | <>
220 | {children}
221 | {/* Here could be any custom modal component */}
222 |
227 | >
228 | );
229 | };
230 | ```
231 |
--------------------------------------------------------------------------------
/ssr/general.md:
--------------------------------------------------------------------------------
1 | ## SSR
2 |
3 | * [General information](#general-information)
4 | * [When should we use it?](#when-should-we-use-it)
5 | * [Cons and pros](#cons-and-pros)
6 |
7 | ## General information
8 |
9 | In web development, SSR stands for Server-Side Rendering. It is a technique used to generate HTML on the server and send it to the client (web browser) as a complete page. With SSR, the server processes the request and dynamically generates the HTML content, including any data or templates, before sending it to the client.
10 |
11 | Here's a brief explanation of how SSR works:
12 |
13 | 1. The client sends a request to the server for a specific URL.
14 | 2. The server receives the request and starts processing it.
15 | 3. The server fetches the necessary data from databases or APIs.
16 | 4. The server renders the HTML template with the fetched data.
17 | 5. The server sends the fully rendered HTML to the client.
18 | 6. The client receives the HTML and displays it in the browser.
19 |
20 | ---
21 |
22 | ## When should we use it?
23 |
24 | 1. Content-driven websites: If your website primarily focuses on delivering content, such as blogs, news articles, or informational pages, SSR can be advantageous. It ensures that search engines can easily index your content, leading to better SEO and organic traffic.
25 | 2. Landing pages: When you have landing pages for marketing or promotional campaigns, SSR can provide a faster and more complete initial page load experience. This helps in capturing the user's attention quickly and increasing the likelihood of conversion.
26 | 3. Websites with static or slowly changing content: If your website's content doesn't change frequently or updates infrequently, SSR can be a suitable choice. It allows you to pre-generate the HTML and serve it to users, reducing the need for client-side rendering and optimizing performance.
27 | 4. SEO-driven websites: If your primary goal is to optimize your website for search engine visibility, SSR can be a valuable technique. By providing fully rendered HTML to search engine crawlers, you enhance the chances of your pages being indexed and ranked higher in search results.
28 | 5. Websites targeting users with slow connections or limited devices: If your target audience includes users with slower internet connections or devices with limited processing power, SSR can provide a better user experience. By reducing the processing required on the client side, you ensure that your website is accessible and usable for a broader range of users.
29 | 6. Websites with personalized or user-specific content: While SSR has limitations with dynamic content, it can still be beneficial when it comes to rendering personalized or user-specific content on the server. By generating the HTML dynamically based on user data, you can deliver personalized experiences without relying solely on client-side rendering.
30 |
31 | ☝️ It's important to consider the specific needs and goals of your project when deciding whether to use SSR. Factors such as the nature of your content, target audience, performance requirements, and SEO priorities should all be taken into account. In some cases, a hybrid approach combining SSR and client-side rendering (CSR) may be appropriate to leverage the benefits of both techniques.
32 |
33 | ---
34 |
35 | ## Cons and pros
36 |
37 | #### Advantages of SSR:
38 |
39 | 1. Improved SEO: SSR makes it easier for search engine crawlers to index and rank your website since the fully rendered HTML is readily available. This can lead to better search engine visibility and organic traffic.
40 | 2. Faster initial page load: With SSR, the server sends a fully rendered HTML page to the client, reducing the time required for JavaScript execution and data fetching. This results in a faster initial page load and a better user experience, especially on slower connections or devices with limited processing power.
41 | 3. Enhanced user experience: SSR can provide a more consistent and usable experience, as the user sees the complete content immediately. There is no need to wait for JavaScript to load and render the page.
42 | 4. Improved social media sharing: When sharing links on social media platforms, SSR ensures that the shared content is accurate and complete. Social media crawlers can scrape the fully rendered HTML, resulting in better previews and information when sharing links.
43 | 5. Compatibility with older browsers and disabled JavaScript: SSR allows your website to be accessible and functional even for users with older browsers or those who have JavaScript disabled. The server generates the complete HTML, ensuring that the content is accessible to a broader range of users.
44 |
45 | #### Disadvantages of SSR:
46 |
47 | 1. Increased server-side processing: SSR requires the server to perform the rendering process for each request. This can put additional load on the server and require more processing resources compared to client-side rendering (CSR).
48 | 2. Limitations in dynamic functionality: SSR may have limitations when it comes to highly dynamic or interactive features that heavily rely on client-side JavaScript. Certain functionalities, such as real-time updates or complex user interactions, may require additional client-side scripting even when using SSR.
49 | 3. Higher complexity in development: Implementing SSR can introduce additional complexity to the development process. It may require specialized frameworks or libraries, and developers need to ensure proper server-side rendering setup and data hydration.
50 | 4. Potential for longer time to first interaction: While SSR reduces the initial page load time, it may take longer for the user to interact with the page fully. This is because client-side JavaScript frameworks need to rehydrate and take over the interactivity after the initial HTML rendering.
51 | 5. Caching challenges: SSR can present challenges with caching. Since the content is generated dynamically on the server, caching can be more complex to implement, especially when dealing with personalized or user-specific content.
--------------------------------------------------------------------------------
/ssr/nextjs/assets/basic-auth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uptechteam/fe-cookbook/8d9a76022430daff58629e264dfcd23b2e281b5e/ssr/nextjs/assets/basic-auth.png
--------------------------------------------------------------------------------
/ssr/nextjs/basic-auth.md:
--------------------------------------------------------------------------------
1 | # Basic auth
2 |
3 | ## What is it?
4 |
5 | HTTP Basic Authentication is a simple authentication mechanism built into the HTTP protocol. It is a way to protect resources on a web server by requiring users to provide a username and password when attempting to access those resources.
6 |
7 | 
8 |
9 | ## Example
10 |
11 | ```typescript
12 | // src/middleware.ts
13 |
14 | import { NextRequest, NextResponse } from "next/server";
15 |
16 | const [AUTH_USER, AUTH_PASS] = (process.env.HTTP_BASIC_AUTH || ":").split(":");
17 |
18 | export function middleware(req: NextRequest) {
19 | if (!process.env.HTTP_BASIC_AUTH) return NextResponse.next();
20 | // HTTP_BASIC_AUTH = login:pass
21 |
22 | const basicAuth = req.headers.get("authorization");
23 |
24 | if (basicAuth) {
25 | const auth = basicAuth.split(" ")[1];
26 | const [user, pwd] = Buffer.from(auth, "base64").toString().split(":");
27 |
28 | if (user === AUTH_USER && pwd === AUTH_PASS) {
29 | return NextResponse.next();
30 | }
31 | }
32 |
33 | return new Response("Auth required", {
34 | status: 401,
35 | headers: {
36 | "WWW-Authenticate": 'Basic realm="Secure Area"',
37 | },
38 | });
39 | }
40 |
41 | export const config = {
42 | matcher: "/",
43 | };
44 | ```
45 |
46 | ### Explanation
47 |
48 | This code appears to be a middleware implemented in a Next.js application to handle HTTP Basic Authentication. Let's break down the code step by step:
49 |
50 | #### Import Statements:
51 |
52 | ```typescript
53 | import { NextRequest, NextResponse } from "next/server";
54 | ```
55 |
56 | The code imports the NextRequest and NextResponse classes from the "next/server" module. These classes are used to handle incoming requests and generate responses in a Next.js application.
57 |
58 | #### Environment Variable Parsing:
59 |
60 | ```typescript
61 | const [AUTH_USER, AUTH_PASS] = (process.env.HTTP_BASIC_AUTH || ":").split(":");
62 | ```
63 |
64 | This code extracts the values of AUTH_USER and AUTH_PASS from the HTTP_BASIC_AUTH environment variable or sets default values to : if the variable is not defined. The HTTP_BASIC_AUTH environment variable is expected to contain a string in the format username:password, and this line splits it into two parts: the username and password.
65 |
66 | #### Middleware Function:
67 |
68 | ```typescript
69 | export function middleware(req: NextRequest) {
70 | ```
71 |
72 | This defines a middleware function that takes a NextRequest object as its argument. Middleware functions in Next.js can intercept and process incoming requests before they reach their destination routes.
73 |
74 | #### Check for the Presence of HTTP_BASIC_AUTH:
75 |
76 | ```typescript
77 | if (!process.env.HTTP_BASIC_AUTH) return NextResponse.next();
78 | ```
79 |
80 | This line checks if the HTTP_BASIC_AUTH environment variable is not defined. If it's not defined, the middleware returns a NextResponse.next() statement. This essentially means that if HTTP Basic Authentication is not configured, the middleware will allow the request to continue to its intended route without any further authentication checks.
81 |
82 | #### Extract Basic Authentication Header:
83 |
84 | ```typescript
85 | const basicAuth = req.headers.get("authorization");
86 | ```
87 |
88 | This line retrieves the "Authorization" header from the incoming request, which typically contains the Basic Authentication credentials.
89 |
90 | #### Parse and Validate Basic Authentication Credentials:
91 |
92 | ```typescript
93 | if (basicAuth) {
94 | const auth = basicAuth.split(" ")[1];
95 | const [user, pwd] = Buffer.from(auth, "base64").toString().split(":");
96 | if (user === AUTH_USER && pwd === AUTH_PASS) {
97 | return NextResponse.next();
98 | }
99 | }
100 | ```
101 |
102 | If the "Authorization" header is present, the code extracts the Base64-encoded credentials from it. It then decodes these credentials and splits them into a user and pwd (password). It compares these credentials with the AUTH_USER and AUTH_PASS values obtained from the environment variables. If they match, it allows the request to proceed by returning NextResponse.next(). If the credentials do not match, it will proceed to return a 401 Unauthorized response.
103 |
104 | #### Return Unauthorized Response:
105 |
106 | ```typescript
107 | return new Response("Auth required", {
108 | status: 401,
109 | headers: {
110 | "WWW-Authenticate": 'Basic realm="Secure Area"',
111 | },
112 | });
113 | ```
114 |
115 | If the credentials do not match or if the "Authorization" header is missing, the middleware returns a 401 Unauthorized response to the client. It includes the "WWW-Authenticate" header, which indicates that Basic Authentication is required and provides a realm name ("Secure Area") for the authentication.
116 |
117 | #### Export Configuration:
118 |
119 | ```typescript
120 | export const config = {
121 | matcher: "/",
122 | };
123 | ```
124 |
125 | The middleware exports a config object with a matcher property set to "/". This specifies that this middleware should be applied to all routes.
126 | In summary, this code is a Next.js middleware that checks for HTTP Basic Authentication credentials in incoming requests. It allows or denies access to routes based on the presence and correctness of these credentials, with the credentials and realm name configured via environment variables. If Basic Authentication is not configured, it allows requests to proceed without authentication.
127 |
--------------------------------------------------------------------------------
/state-management/context/overview.md:
--------------------------------------------------------------------------------
1 | # React Context API
2 |
3 | Context API has been introduced in React v16.3 and as the documentation states, “Context provides a way to pass data through the component tree without having to pass props down manually at every level”.
4 |
5 | Although React Context is simple to implement and great for certain types of apps, it’s built in such a way that every time the value of the context changes, the component consumer rerenders.
6 |
7 | Here is an official [documentation](https://react.dev/reference/react/createContext).
8 |
9 | ## Pros and cons of React Context API
10 |
11 | ### Pros
12 |
13 | - Resourceful and practical in small applications with minimal state changes.
14 | - Easy to understand and handle even for beginners.
15 | - Minimal configuration, only for creating the context.
16 | - Well documented.
17 | - Can use a lot of local contexts to handle separate logic tasks.
18 | - Can be easily used with async tasks.
19 | - Out-of-the-box, which leads to smaller packages and better project maintenance.
20 |
21 | ### Cons
22 |
23 | - Not designed to use with frequently refreshed or changed data.
24 | - Could be more challenging to maintain in complex apps, especially if we have custom solutions and helpers.
25 |
26 | ## Example of using React Context API
27 |
28 | Make sure you configured your browser for showing highlighted components after rerender. Here is an example of how to do it in Google Chrome DevTools:
29 |
30 | 
31 |
32 | In the example below we consider a simple form with a couple of inputs.
33 |
34 | 
35 |
36 | As you can see all of the page was rerendered after some of the text inputs were changed.
37 |
38 | A full demo for this solution is [here](https://fast-context.vercel.app/).
39 |
40 | Every time the value of the context changes, all components’ consumers will rerender.
41 | Here is code for this example:
42 |
43 | ```
44 |
45 | import { useState, createContext, useContext, memo } from "react";
46 |
47 | function useStoreData() {
48 | const store = useState({
49 | first: "",
50 | last: "",
51 | });
52 | return store;
53 | }
54 |
55 | type UseStoreDataReturnType = ReturnType;
56 |
57 | const StoreContext = createContext(null);
58 |
59 | const TextInput = ({ value }: { value: "first" | "last" }) => {
60 | const [store, setStore] = useContext(StoreContext)!;
61 | return (
62 |
123 |
124 | );
125 | }
126 |
127 | export default App;
128 |
129 | ```
130 |
131 | See the full code on [GitHub](https://github.com/MaxKalashnyk/fast-context/blob/main/src/Default.tsx).
132 |
--------------------------------------------------------------------------------
/state-management/context/react-context-useReducer.md:
--------------------------------------------------------------------------------
1 | # React Context API with the useReducer hook
2 |
3 | React Context API and the `useReducer` hook are commonly used together to manage state at a global level in React applications. The `useReducer` hook provides a way to manage complex state and state transitions, while the Context API allows you to propagate that state to any component that needs it without passing props through intermediate components.
4 |
5 | Here is an official [documentation](https://react.dev/learn/scaling-up-with-reducer-and-context) of this approach.
6 |
7 | And here's an example of how you can use the `useReducer` hook with the Context API:
8 |
9 | 1. Create a folder "contexts" in your app repo.
10 | 2. Create a subfolder with the appropriate name of your context (e.g. Counter).
11 | 3. In this folder we usually store the `Counter.tsx` file and the `types.ts` file.
12 | 4. Update your `Counter.tsx` file(or any name you prefer) to define your global state and actions:
13 |
14 | ```
15 | import { createContext, useReducer, FC, useContext } from "react";
16 | import { CounterActions } from "./types";
17 |
18 | // Define the initial state
19 | const initialState: IState = {
20 | count: 0,
21 | };
22 |
23 | const CounterDispatch = createContext(() => ({
24 | type: Actions.Noop,
25 | }));
26 |
27 | const CounterContext = createContext(defaultState);
28 |
29 | export const Reducer: React.Reducer = (state, action) => {
30 | switch (action.type) {
31 | case CounterActions.Increment:
32 | return { ...state, count: state.count + 1 };
33 | case CounterActions.Decrement:
34 | return { ...state, count: state.count - 1 };
35 | default:
36 | return state;
37 | }
38 | };
39 |
40 | export const Context: FC = ({ children }) => {
41 | const [state, dispatch] = useReducer>(
42 | Reducer,
43 | defaultState
44 | );
45 |
46 | return (
47 |
48 |
49 | {children}
50 |
51 |
52 | );
53 | };
54 |
55 | export const useCounterState = (): IState => {
56 | const ctx = useContext(CounterContext);
57 | if (ctx === undefined) {
58 | throw new Error("useState must be used within a Provider");
59 | }
60 | return ctx;
61 | };
62 |
63 | export const useCounterDispatch = (): ActionDispatch => {
64 | const dispatch = useContext(CounterDispatch);
65 | if (dispatch === undefined) {
66 | throw new Error("useDispatch must be used within a Provider");
67 | }
68 | return dispatch;
69 | };
70 |
71 | ```
72 |
73 | 5. Update your `types.ts` file:
74 |
75 | ```
76 |
77 | import { ReactNode } from "react";
78 |
79 | export enum CounterActions {
80 | Increment = "INCREMENT",
81 | Decrement = "DECREMENT",
82 | Noop = "noop",
83 | }
84 |
85 | export interface IState {
86 | count: number;
87 | }
88 |
89 | export interface IContext {
90 | children?: ReactNode;
91 | }
92 |
93 | export interface IOperation {
94 | type: typeof CounterActions.Increment | typeof CounterActions.Decrement;
95 | // payload: number; You can also add types for your payloads
96 | }
97 |
98 | export interface INoopAction {
99 | type: typeof CounterActions.Noop;
100 | }
101 |
102 | export type CounterActionTypes = IOperation | INoopAction;
103 |
104 | export type ActionDispatch = (arg: CounterActionTypes) => CounterActionTypes;
105 |
106 | ```
107 |
108 | 6. Wrap your root component with prior created providers:
109 |
110 | ```
111 |
112 | import ReactDOM from 'react-dom';
113 | import App from './App';
114 | import { Context } from '~/contexts/CounterContext';
115 |
116 | ReactDOM.render(
117 |
118 |
119 | ,
120 | document.getElementById('root')
121 | );
122 |
123 | ```
124 |
125 | Note than you can wrap not only root component of your app but other different pages:
126 |
127 | ```
128 |
129 |
130 |
131 |
132 |
133 | ```
134 |
135 | 7. In any component that needs access to the global state, import the `Context` and use the `useCounterState` and the `useCounterDispatch` hooks to access the state and dispatch function:
136 |
137 | ```
138 |
139 | // MyComponent.js
140 | import { useContext, FC } from 'react';
141 | import { useCounterState, useCounterDispatch } from '~/contexts/CounterContext';
142 |
143 | export const MyComponent: FC = () => {
144 | const { count } = useCounterState();
145 | const dispatch = useCounterDispatch();
146 |
147 | const handleIncrement = () => {
148 | dispatch({ type: CounterActions.Increment });
149 | };
150 |
151 | const handleDecrement = () => {
152 | dispatch({ type: CounterActions.Decrement });
153 | };
154 |
155 | return (
156 |
157 |
Count: {count}
158 |
159 |
160 |
161 | );
162 | };
163 |
164 | ```
165 |
166 | 8. More information you can find [here](https://react.dev/learn/scaling-up-with-reducer-and-context).
167 |
--------------------------------------------------------------------------------
/state-management/redux-toolkit/overview.md:
--------------------------------------------------------------------------------
1 | # Redux Toolkit
2 |
3 | 1. [General information](#general-info)
4 | 2. [Setup](#setup)
5 | 3. [Usage](#usage)
6 | 4. [Examples](#examples)
7 |
8 | ## General information
9 |
10 | Redux Toolkit is a popular opinionated package that simplifies the development process when using Redux in a React application. It was created by the Redux team to address common issues and boilerplate code that developers encountered when using Redux.
11 |
12 | Here is a [link](https://redux-toolkit.js.org/introduction/getting-started) to the ofiicial documentation.
13 |
14 | 
15 | This screenshot was taken from [this](https://www.udemy.com/course/react-redux/) course.
16 |
17 | ## Setup
18 |
19 | The recommended way to start new apps with React and Redux is by using [official Redux+TS template for Vite](https://github.com/reduxjs/redux-templates), or by creating a new Next.js project using [Next's `with-redux` template](https://github.com/vercel/next.js/tree/canary/examples/with-redux).
20 |
21 | Both of these already have Redux Toolkit and React-Redux configured appropriately for that build tool, and come with a small example app that demonstrates how to use several of Redux Toolkit's features.
22 |
23 | ```bash
24 | # Vite with our Redux+TS template
25 | # (using the `degit` tool to clone and extract the template)
26 | npx degit reduxjs/redux-templates/packages/vite-template-redux my-app
27 |
28 | # Next.js using the `with-redux` template
29 | npx create-next-app --example with-redux my-app
30 | ```
31 |
32 | Redux Toolkit is available as a package on NPM for use with a module bundler or in a Node application:
33 |
34 | ```bash
35 | pnpm install @reduxjs/toolkit react-redux
36 | ```
37 |
38 | ## Usage
39 |
40 | Here is a [link](https://redux-toolkit.js.org/tutorials/quick-start) of how you can configure this library on your project.
41 |
42 | ## Examples
43 |
44 | These examples were taken from [this](https://www.udemy.com/course/react-redux/) course which was previously mentioned.
45 |
46 | 1. Playlists app.
47 |
48 | In the example below we build a very simple playlist application whenever a user clicks on add movie. We are going to randomly generate a movie name and add it into a list. Whenever a movie is added, we're going to see a red X button to the very right hand side here. If we click on that button, we delete that movie.
49 |
50 | Here is a mockup of this app:
51 |
52 | 
53 |
54 | And [demo](https://codesandbox.io/s/completed-media-project-zyz2mx?file=/src/App.js) with the source code.
55 |
56 | 2. Car cost app.
57 |
58 | Here we have an application which allows a user to track a couple of cars they own.
59 | The user can type in the name of the car and the value of the car and this is intended to be the dollar value or whatever currency you are using.
60 |
61 | When we click on Submit, we're going to take the car name and the car value and add it in to the list of cars displayed down here towards the bottom. The user can also delete any cars that they add. And the total down here should automatically be updated.
62 |
63 | We're going to make sure that the list of cars can be searchable.
64 |
65 | We are going to allow vehicles with identical names to be added into this application, but as a nice little kind of extra thing for our users, we're just going to highlight to them if they are adding in a car with a name that already exists.
66 |
67 | Here is a mockup of this app:
68 |
69 | 
70 |
71 | And [demo](https://codesandbox.io/s/vigorous-cartwright-p33tkx) with the source code.
72 |
--------------------------------------------------------------------------------
/state-management/redux-toolkit/rtk-query.md:
--------------------------------------------------------------------------------
1 | # Redux Toolkit Query
2 |
3 | 1. [General information](#general-info)
4 | 2. [Setup](#setup)
5 | 3. [Usage](#usage)
6 | 4. [Example](#example)
7 |
8 | ## General information
9 |
10 | RTK Query is a powerful data fetching and caching tool. It is designed to simplify common cases for loading data in a web application, eliminating the need to hand-write data fetching & caching logic yourself.
11 | RTK Query is an optional addon included in the Redux Toolkit package, and its functionality is built on top of the other APIs in Redux Toolkit.
12 |
13 | Here is a [link](https://redux-toolkit.js.org/rtk-query/overview) to the ofiicial documentation.
14 |
15 | Web applications normally need to fetch data from a server in order to display it. They also usually need to make updates to that data, send those updates to the server, and keep the cached data on the client in sync with the data on the server. This is made more complicated by the need to implement other behaviors used in today's applications:
16 |
17 | - Tracking loading state in order to show UI spinners
18 | - Avoiding duplicate requests for the same data
19 | - Optimistic updates to make the UI feel faster
20 | - Managing cache lifetimes as the user interacts with the UI
21 |
22 | 
23 | This screenshot was taken from [this](https://www.udemy.com/course/react-redux/) course.
24 |
25 | ## Setup
26 |
27 | To install RTK Query (Redux Toolkit Query), you need to follow these steps:
28 |
29 | 1. Install Redux Toolkit: RTK Query relies on Redux Toolkit, so make sure you have Redux Toolkit installed in your project. If you haven't installed Redux Toolkit yet, you can do so with the following command:
30 |
31 | ```bash
32 | pnpm install @reduxjs/toolkit
33 | ```
34 |
35 | 2. Install RTK Query: After installing Redux Toolkit, you can install RTK Query by running the following command:
36 |
37 | ```bash
38 | pnpm install @reduxjs/toolkit-query
39 | ```
40 |
41 | ## Usage
42 |
43 | Here is a [link](https://redux-toolkit.js.org/tutorials/rtk-query/) of how you can configure this library on your project.
44 |
45 | Also, you can follow these guides here:
46 | [RTK Query Basics](https://redux.js.org/tutorials/essentials/part-7-rtk-query-basics)
47 |
48 | In the example above pay attention to the powerful advantage of this library - automatic hooks generation when we add [Query](https://redux.js.org/tutorials/essentials/part-7-rtk-query-basics#adding-the-single-post-query-endpoint) and [Mutation](https://redux.js.org/tutorials/essentials/part-7-rtk-query-basics#adding-the-new-post-mutation-endpoint) endpoints.
49 |
50 | Also, in the example above pay attention to the section about the refreshing caching data topics (both manual and automatic refreshing with cache invalidation using tags). More info is [here](https://redux.js.org/tutorials/essentials/part-7-rtk-query-basics#refreshing-cached-data).
51 |
52 | Here you can find more complex topics of using RTK Query to simplify your codebase and improve user experience (especially Invalidating Specific Items and Advanced cache updates):
53 | [RTK Query Advanced Patterns](https://redux.js.org/tutorials/essentials/part-8-rtk-query-advanced)
54 |
55 | ## Example
56 |
57 | This example was taken from [this](https://www.udemy.com/course/react-redux/) course.
58 |
59 | ### User photo albums app
60 |
61 | Here is a mockup of this app:
62 |
63 | 
64 |
65 | In the example below we build the app where we will make a network request to an outside API and fetch a list of users and show them on the screen. We're going to have a button that we can click on to add in a new user. Whenever that button is clicked, we're going to make a request to create a new user, and we're going to give that user a randomly generated name. Next to every user, we're going to have a little button to delete the user.
66 |
67 | As we show these users, you notice there are these little kind of expander arrows, arrows over here to the right hand side. So if we expand this first section right here, we're going to display a list of photo albums that have been created by this user.
68 | So an album is going to be a collection of different photos. For every album this user has created, we're going to show a very similar little expander panel right here. We can delete an album that has been created by clicking on that button. We can expand the album by clicking over here and we can add in brand new albums that are tied to this user by clicking on the `Add album` button.
69 | And then finally, if the user clicks on an album to expand it, we're going to show a collection of photos that have been created inside of that album. And likewise, very similar to adding new users and new albums, we can add in new photos as well.
70 |
71 | So all the data is essentially randomly generated, but we are going to save it to an outside API so we can fetch these randomly generated records at some point in the future.
72 |
73 | All of our data will be stored on an outside server. For this purpose we use JSON server library. This is a very simple API server that we can use to store any kind of data. So on the server, we're going to have a list of users albums and photos. And we're going to make requests to fetch those lists and store them inside of our Redux store.
74 |
75 | And then once they're inside of our store, of course, we're going to access that data inside of React Component and render the list of users albums or photos out.
76 |
77 | 🚨 Here we use Async Thunk functions (Redux Toolkit) to handle users and RTK Query to handle albums and photos. 🚨
78 |
79 | [Demo](https://codesandbox.io/p/sandbox/confident-farrell-93xx5j) with the source code.
80 |
81 | 🚨🚨🚨 Don't forget to run the server (`npm run start:server`) in order to make this app work correctly.
82 |
--------------------------------------------------------------------------------
/styling/MUI.md:
--------------------------------------------------------------------------------
1 | # MUI
2 |
3 | 1. [Installation](#installation)
4 | 2. [Basic usage](#basic-usage)
5 | 3. [Styling](#styling)
6 | 4. [Theming](#theming)
7 | 5. [Organizing files structure](#organizing-files-structure)
8 | 6. [Example of files](#example-of-files)
9 | 7. [Using MUI with TypeScript](#using-mui-with-typescript)
10 |
11 | ## Installation
12 |
13 | Run `pnpm install @mui/material @emotion/react @emotion/styled`.
14 |
15 | ## Basic usage
16 |
17 | Import the MUI components you want to use in your React components. For example, to use a button, you can import it like this:
18 | ```js
19 | import { Button } from '@mui/material';
20 |
21 | // Usage
22 |
23 | ```
24 |
25 | ## Styling
26 |
27 | > **Note:** Inline styles only for the synopsis, use only `styled` function in your project.
28 |
29 | * You can pass a style prop to a component to apply custom styles. For example:
30 | ```js
31 |
32 | ```
33 |
34 | * MUI components come with default styles, which you can override using the sx prop. The sx prop accepts an object containing style properties. For example:
35 | ```js
36 |
37 | ```
38 |
39 | * MUI provides the styled function from the @emotion/styled package, allowing you to create custom styles for MUI components. You can define styles and create a custom component using the styled function. For example:
40 | ```js
41 | import { styled } from '@mui/system';
42 |
43 | const StyledButton = styled(Button)({
44 | backgroundColor: 'blue',
45 | color: 'white',
46 | });
47 |
48 | // Usage
49 | Styled Button
50 | ```
51 |
52 | ## Theming
53 |
54 | You can create a theme using the createTheme function from @mui/material/styles. For example:
55 | ```js
56 | import { createTheme, ThemeProvider } from '@mui/material/styles';
57 |
58 | const theme = createTheme({
59 | palette: {
60 | primary: {
61 | main: '#ff0000',
62 | },
63 | },
64 | });
65 |
66 | // Usage
67 |
68 | {/* Your application */}
69 |
70 | ```
71 |
72 | > Information about all available components you can find [here](https://mui.com/)
73 |
74 | ## Organizing files structure
75 |
76 | 1. Create separate folder called *styles* in *src*
77 | 2. Files structure should be similar to the following:
78 |
79 |
80 | ## Example of files
81 |
82 | ```js
83 | // breakpoints.js
84 |
85 | // use if you need to replace default breakpoints:
86 | // xs, extra-small: 0px
87 | // sm, small: 600px
88 | // md, medium: 900px
89 | // lg, large: 1200px
90 | // xl, extra-large: 1536px
91 |
92 | export const breakpoints = {
93 | values: {
94 | xs: 0,
95 | sm: 576,
96 | md: 992,
97 | lg: 1200,
98 | xl: 1400,
99 | },
100 | };
101 |
102 | export const getBreakpoint = (value) =>
103 | `@media (min-width:${breakpoints.values[value]}px)`;
104 |
105 | ```
106 |
107 | ```js
108 | // components.js
109 |
110 | // use to set up base appearance of components
111 |
112 | export const components = {
113 | MuiCssBaseline: {
114 | styleOverrides: {
115 | ...
116 |
117 | MuiButtonBase: {
118 | styleOverrides: {
119 | root: {
120 | "&.MuiButton-root": {
121 | textTransform: "none",
122 | ...
123 |
124 | ```
125 |
126 | ```js
127 | // mixins.js
128 |
129 | // use if you need to extend default mixins
130 |
131 | export const mixins = {
132 | toolbar: {
133 | minHeight: 50,
134 | "@media (min-width: 0px) and (orientation: landscape)": {
135 | minHeight: 50,
136 | },
137 | "@media (min-width: 600px)": {
138 | minHeight: 50,
139 | },
140 | },
141 | };
142 | ```
143 |
144 | ```js
145 | // palette.js
146 |
147 | // use to define colors set
148 |
149 | export const palette = {
150 | common: {
151 | white: "#fff",
152 | black: "#000",
153 | },
154 | primary: {
155 | main: "#41479B",
156 | dark: "#333",
157 | },
158 | secondary: {
159 | main: "#44756B",
160 | },
161 | ...
162 |
163 | ```
164 | > If you want to use custom colors, [here](https://mui.com/material-ui/customization/palette/#adding-new-colors) is a detailed instruction.
165 |
166 | ```js
167 | // shape.js
168 |
169 | // use if you want to define borderRadius
170 |
171 | export const shape = {
172 | borderRadius: 8,
173 | };
174 | ```
175 |
176 | ```js
177 | // typography.js
178 |
179 | // use to define typography for different variants
180 |
181 | const h1 = {
182 | fontWeight: 600,
183 | fontSize: "28px",
184 | lineHeight: "35px",
185 | };
186 |
187 | const h2 = {
188 | fontWeight: 600,
189 | fontSize: "24px",
190 | lineHeight: "34px",
191 | };
192 |
193 | ...
194 |
195 | export const fontSizes = {
196 | h1,
197 | h2,
198 | ...
199 | };
200 |
201 | export const typography = {
202 | ...fontSizes,
203 | // general properties applied to all variants
204 | fontFamily: "Arial, sans-serif",
205 | fontWeightRegular: 400,
206 | fontWeightMedium: 600,
207 | fontWeightBold: 700,
208 | fontSize: 13,
209 | };
210 | ```
211 |
212 | ```js
213 | // theme.js
214 |
215 | // use to create theme and unite all features defined above
216 |
217 | import { createTheme } from "@mui/material/styles";
218 | import { palette } from "./palette";
219 | import { shape } from "./shape";
220 | import { breakpoints } from "./breakpoints";
221 | import { typography } from "./typography";
222 | import { components } from "./components";
223 | import { mixins } from "./mixins";
224 |
225 | const theme = createTheme({
226 | palette,
227 | spacing: 4, // uses for defining coeficient of spacing
228 | shape,
229 | breakpoints,
230 | typography,
231 | components,
232 | mixins,
233 | });
234 |
235 | export default theme;
236 | ```
237 |
238 | ## Using MUI with TypeScript
239 |
240 | * If you need to pass custom props to MUI components, you can create an interface that extends the original component's props and use it in your component. For example:
241 |
242 | ```ts
243 | import { TextField, TextFieldProps } from '@mui/material';
244 |
245 | interface MyTextFieldProps extends TextFieldProps {
246 | // Custom props
247 | placeholderText: string;
248 | }
249 |
250 | const MyTextField: React.FC = ({ placeholderText, ...rest }) =>
251 | ;
252 | ```
253 |
254 | * If you're using `styled` function with dynamic props, you need to define additional props. For example:
255 |
256 | ```ts
257 | import Button from '@mui/material/Button';
258 | import { styled } from '@mui/material/styles';
259 |
260 | interface IButtonProps {
261 | isActive: boolean;
262 | }
263 |
264 | const ButtonStyled = styled(Button)(({ theme, isActive }) => ({
265 | color: isActive ? theme.palette.green : theme.palette.grey
266 | }))
267 | ```
268 |
269 | * If you need to expand default theme options you need to declare them in `theme.ts` file. For example:
270 |
271 | ```ts
272 | // theme.ts
273 |
274 | interface Palette {
275 | others: {
276 | completed: CSSProperties["color"];
277 | completedStroke: CSSProperties["color"];
278 | draft: CSSProperties["color"];
279 | draftStroke: CSSProperties["color"];
280 | processing: CSSProperties["color"];
281 | }
282 | }
283 |
284 | interface PaletteOptions {
285 | others: {
286 | completed: CSSProperties["color"];
287 | completedStroke: CSSProperties["color"];
288 | draft: CSSProperties["color"];
289 | draftStroke: CSSProperties["color"];
290 | processing: CSSProperties["color"];
291 | }
292 | }
293 |
294 | interface PaletteColorOptions {
295 | main: CSSProperties["color"];
296 | light?: CSSProperties["color"];
297 | dark?: CSSProperties["color"];
298 | contrastText?: CSSProperties["color"];
299 | secondary?: CSSProperties["color"];
300 | }
301 |
302 | export const theme = createTheme({
303 | // your theme config
304 | });
305 | ```
306 |
307 | > More detailed instruction you can find [here](#https://mui.com/material-ui/guides/typescript/).
308 |
--------------------------------------------------------------------------------
/styling/dark-mode.md:
--------------------------------------------------------------------------------
1 | # Dark Mode in React App
2 |
3 | 1. [CSS Variables with Context](#css-variables-with-context)
4 | 2. [Styled components](#styled-components)
5 | 3. [MUI](#mui)
6 | 4. [Media Queries](#media-queries)
7 |
8 | ## CSS Variables with Context
9 |
10 | 1\. Create a context or state management system to manage the dark mode state across your app. This can be done using React's built-in Context API, Redux, or any other state management library of your choice. The context/state will store a boolean value indicating whether the dark mode is enabled or disabled.
11 |
12 | ```javascript
13 | // DarkModeContext.js
14 | import { createContext, useState } from "react";
15 |
16 | export const DarkModeContext = createContext();
17 |
18 | export const DarkModeProvider = ({ children }) => {
19 | const [darkMode, setDarkMode] = useState(false);
20 |
21 | const toggleDarkMode = () => {
22 | setDarkMode((prevMode) => !prevMode);
23 | };
24 |
25 | return (
26 |
27 | {children}
28 |
29 | );
30 | };
31 | ```
32 |
33 | 2\. Wrap your app component with the **DarkModeProvider** in your main **index.js** file or at the top level of your component hierarchy.
34 |
35 | ```javascript
36 | import ReactDOM from "react-dom";
37 | import App from "./App";
38 | import { DarkModeProvider } from "./DarkModeContext";
39 |
40 | ReactDOM.render(
41 |
42 |
43 | ,
44 | document.getElementById("root")
45 | );
46 | ```
47 |
48 | 3\. In any component where you want to access or update the dark mode state, import the **DarkModeContext** and use the **useContext** hook to access the context values.
49 |
50 | ```javascript
51 | import { useContext } from "react";
52 | import DarkModeContext from "./DarkModeContext";
53 |
54 | function MyComponent() {
55 | const { darkMode, toggleDarkMode } = useContext(DarkModeContext);
56 |
57 | return (
58 |
59 | {/* Your component content */}
60 |
63 |
64 | );
65 | }
66 |
67 | export default MyComponent;
68 | ```
69 |
70 | 4\. In your app's main stylesheet or style definition file, define two sets of styles: one for light mode and one for dark mode. You can use CSS variables to make it easier to switch between the two modes.
71 |
72 | ```css
73 | /* App.css */
74 | .App {
75 | background-color: var(--bg-color);
76 | color: var(--text-color);
77 | /* Rest of your styles */
78 | }
79 |
80 | /* Light mode */
81 | :root {
82 | --bg-color: #ffffff;
83 | --text-color: #000000;
84 | /* Rest of your light mode styles */
85 | }
86 |
87 | /* Dark mode */
88 | [data-dark-mode="true"] {
89 | --bg-color: #000000;
90 | --text-color: #ffffff;
91 | /* Rest of your dark mode styles */
92 | }
93 | ```
94 |
95 | ## Styled components
96 |
97 | 1\. Install styled-components: Install the styled-components library in your project by running the following command in your project directory:
98 |
99 | ```plaintext
100 | pnpm install styled-components
101 | ```
102 |
103 | 2\. Create a ThemeProvider: In your project, create a file called **ThemeProvider.js** (or any other name you prefer) in a suitable directory. In this file, you will define your theme and wrap your app with a **ThemeProvider** component provided by styled-components.
104 |
105 | ```javascript
106 | // ThemeProvider.js
107 |
108 | import { ThemeProvider as StyledThemeProvider } from "styled-components";
109 |
110 | // Define your theme object
111 | const lightTheme = {
112 | // Define your light theme styles
113 | body: "#ffffff",
114 | text: "#000000",
115 | };
116 |
117 | const darkTheme = {
118 | // Define your dark theme styles
119 | body: "#333333",
120 | text: "#ffffff",
121 | };
122 |
123 | // Create a ThemeProvider component
124 | const ThemeProvider = ({ children, isDarkMode }) => {
125 | // Use the isDarkMode prop to determine which theme to use
126 | const theme = isDarkMode ? darkTheme : lightTheme;
127 |
128 | return {children};
129 | };
130 |
131 | export default ThemeProvider;
132 | ```
133 |
134 | 3\. Create a GlobalStyle component: In the same directory as **ThemeProvider.js**, create another file called **GlobalStyle.js**. This file will contain global CSS styles that will be applied to your entire app.
135 |
136 | ```javascript
137 | // GlobalStyle.js
138 |
139 | import { createGlobalStyle } from "styled-components";
140 |
141 | // Define your global styles
142 | const GlobalStyle = createGlobalStyle`
143 | body {
144 | background-color: ${(props) => props.theme.body};
145 | color: ${(props) => props.theme.text};
146 | }
147 | `;
148 |
149 | export default GlobalStyle;
150 | ```
151 |
152 | 4\. Implement dark mode toggle: In your main app component, create a state variable to store the current dark mode state. Then, create a toggle function to switch between light and dark mode.
153 |
154 | ```javascript
155 | import { useState } from "react";
156 | import ThemeProvider from "./ThemeProvider";
157 | import GlobalStyle from "./GlobalStyle";
158 |
159 | const App = () => {
160 | const [isDarkMode, setIsDarkMode] = useState(false);
161 |
162 | const toggleDarkMode = () => {
163 | setIsDarkMode((prev) => !prev);
164 | };
165 |
166 | return (
167 |
168 |
169 |
Your App
170 |
171 |
172 |
173 |
174 | );
175 | };
176 |
177 | export default App;
178 | ```
179 |
180 | 5\. Style your components: Now you can start styling your components using styled-components and access the theme object within your styles.
181 |
182 | ```javascript
183 | import styled from "styled-components";
184 |
185 | const Button = styled.button`
186 | background-color: ${(props) => props.theme.body};
187 | color: ${(props) => props.theme.text};
188 | /* Other button styles */
189 | `;
190 | ```
191 |
192 | ## MUI
193 |
194 | 1\. If you haven't already, install Material-UI in your React project by running the following command:
195 |
196 | ```plaintext
197 | pnpm install @mui/material @emotion/react @emotion/styled
198 | ```
199 |
200 | 2\. Create a Dark Mode Theme: In your **theme.js** file (or wherever you defined your theme), add the configuration for the dark mode. Modify your theme object to include the palette configuration for both light and dark modes. For example:
201 |
202 | ```javascript
203 | import { createTheme } from "@mui/material/styles";
204 |
205 | const lightTheme = createTheme({
206 | palette: {
207 | mode: "light",
208 | primary: {
209 | main: "#2196f3",
210 | },
211 | // Add more palette colors if needed
212 | },
213 | });
214 |
215 | // Dark mode configuration
216 | const darkTheme = createTheme({
217 | palette: {
218 | mode: "dark",
219 | primary: {
220 | main: "#64b5f6",
221 | },
222 | // Add more palette colors if needed
223 | },
224 | });
225 |
226 | export { lightTheme, darkTheme };
227 | ```
228 |
229 | 3\. Toggle Between Themes: Update your **App** component to toggle between the light and dark themes based on the current mode. You can use the **ThemeProvider** component from MUI to dynamically switch between themes. Here's an example:
230 |
231 | ```javascript
232 | import { useState } from "react";
233 | import { ThemeProvider } from "@mui/material/styles";
234 | import { lightTheme, darkTheme } from "./theme"; // Path to your theme file
235 | import DarkModeToggle from "./DarkModeToggle";
236 |
237 | function App() {
238 | const [isDarkMode, setIsDarkMode] = useState(false);
239 |
240 | const toggleDarkMode = () => {
241 | setIsDarkMode((prevMode) => !prevMode);
242 | };
243 |
244 | return (
245 |
246 |
247 |
My App
248 |
249 | {/* Rest of your app */}
250 |
251 |
252 | );
253 | }
254 |
255 | export default App;
256 | ```
257 |
258 | 4\. To style components specifically for dark mode, you can leverage MUI's built-in classes and styles. MUI provides a **styled** function that allows you to define component styles conditionally based on the theme. Here's an example:
259 |
260 | ```javascript
261 | import { styled } from "@mui/material/styles";
262 | import { Box } from "@mui/material";
263 |
264 | export const StyledContainer = styled(Box)(({ theme }) => ({
265 | color: theme.palette.mode === "dark" ? "#ffffff" : "#000000",
266 | backgroundColor: theme.palette.mode === "dark" ? "#333333" : "#f5f5f5",
267 | }));
268 | ```
269 |
270 | ## Media Queries
271 |
272 | You can use a `media query` to apply different styles based on the user's color scheme preference. A user indicates their preference through an **operating system setting** (e.g. light or dark mode) or a **user agent setting**. Styles will change automatically depending on user's color scheme preference.
273 |
274 | ```css
275 | @media (prefers-color-scheme: dark) {
276 | /* Styles for dark mode */
277 | body {
278 | background-color: #222;
279 | color: #fff;
280 | }
281 | }
282 |
283 | @media (prefers-color-scheme: light) {
284 | /* Styles for light mode */
285 | body {
286 | background-color: #fff;
287 | color: #333;
288 | }
289 | }
290 | ```
291 |
--------------------------------------------------------------------------------
/styling/general-recommendations.md:
--------------------------------------------------------------------------------
1 | # General recommendations
2 |
3 | 1. Use styled-components or MUI only.
4 | 2. Keep colors in separate file, like js object.
5 | 3. Keep theme in separate file, like js object.
6 | 4. Keep styles related to Component in file **styles.js** near the Component in the same folder.
7 |
--------------------------------------------------------------------------------
/ui-components/date-time-pickers.md:
--------------------------------------------------------------------------------
1 | # Date and time pickers
2 |
3 | 1. [Well-known date and time picker libraries](#well-known-date-and-time-picker-libraries)
4 | - [React Datepicker](#react-datepicker)
5 | - [MUI Pickers](#mui-pickers)
6 | - [React-Dates](#react-dates)
7 | - [React-DateTime-Picker](#react-datetime-picker)
8 | - [React-Day-Picker](#react-day-picker)
9 | 2. [Date utility libraries](#date-utility-libraries)
10 | - [Date-fns](#date-fns)
11 | - [Luxon](#luxon)
12 | - [Day.js](#day.js)
13 | 3. [Summary](#summary)
14 |
15 | ## Well-known date and time picker libraries
16 |
17 | Here are some well-known date and time picker libraries for React:
18 |
19 | ### React Datepicker
20 |
21 | **React Datepicker** is a lightweight and easy-to-use library for picking dates in a React application. It provides a simple calendar view that allows users to select dates from a popup.
22 |
23 | **Features**:
24 |
25 | - Customizable date format.
26 | - Support for selecting single dates or date ranges.
27 | - Localization support for different languages.
28 | - Support for disabling specific dates or date ranges.
29 | - Easy integration with React forms.
30 |
31 | Documentation: https://reactdatepicker.com/
32 |
33 | ---
34 |
35 | ### MUI Pickers
36 |
37 | **MUI Pickers** is an extension of the MUI library that provides reusable and customizable date and time pickers with a Material Design look and feel.
38 |
39 | > **Note!** The Date and Time Pickers are available in two packages:
40 |
41 | > - `@mui/x-date-pickers`, which is MIT licensed (free forever) and contains all the components to edit a date and/or a time.
42 | > - `@mui/x-date-pickers-pro`, which is commercially licensed and contains additional components to edit date and/or time ranges.
43 |
44 | **Features:**
45 |
46 | - Date and time pickers with different styles (dialog, inline, static, etc.).
47 | - Localization support.
48 | - Date range selection.
49 | - Customizable date and time formats.
50 | - Integration with MUI components.
51 |
52 | Documentation: https://mui.com/x/react-date-pickers/getting-started/
53 |
54 | ---
55 |
56 | ### React-DateTime-Picker
57 |
58 | **React-DateTime-Picker** is a flexible date and time picker library for React. It offers both date and time selection capabilities and is designed to be customizable to suit different project requirements.
59 |
60 | **Features:**
61 |
62 | - Support for selecting date, time, or both.
63 | - Customizable date and time formats.
64 | - Time interval configuration (e.g., 5-minute increments).
65 | - Ability to disable specific dates or time intervals.
66 | - Localization support.
67 |
68 | Documentation: https://projects.wojtekmaj.pl/react-datetime-picker
69 |
70 | ---
71 |
72 | ### React-Dates
73 |
74 | **React-Dates** is a powerful date picker library developed by Airbnb. It provides a collection of pre-built components to pick single dates, date ranges, and even allows selecting multiple dates.
75 |
76 | **Features:**
77 |
78 | - Date range selection with start and end dates.
79 | - Customizable calendar presentation and layout.
80 | - Support for choosing single dates and multiple dates.
81 | - Localization and internationalization support.
82 | - Ability to disable specific dates or date ranges.
83 |
84 | Documentation: https://github.com/airbnb/react-dates
85 |
86 | ---
87 |
88 | ### React-Day-Picker
89 |
90 | **React-Day-Picker** is a straightforward and lightweight date picker for React. It aims to be easy to use and easy to customize.
91 |
92 | **Features:**
93 |
94 | - Single date selection.
95 | - Customizable date format.
96 | - Ability to disable specific dates or date ranges.
97 | - Basic localization support.
98 |
99 | Documentation: https://github.com/gpbl/react-day-picker
100 |
101 | ## Date utility libraries
102 |
103 | These libraries provide various functionalities to work with dates and time in React applications. Here are some popular date-related JS libraries:
104 |
105 | ### Date-fns
106 |
107 | **date-fns** is a popular and comprehensive date utility library for JavaScript. It is designed to handle various common date and time-related operations, making it easier to work with dates in your JavaScript and React applications. Date-fns aims to be simple, functional, and focused on providing an intuitive API for working with dates.
108 |
109 | **Pros:**
110 |
111 | - Lightweight and tree-shakable, resulting in smaller bundle sizes.
112 | - Comprehensive functionality for date manipulation and formatting.
113 | - Follows functional programming principles, leading to predictable and immutable date operations.
114 | - Good TypeScript support with built-in type declarations.
115 | - Well-maintained and actively developed, with a growing community.
116 |
117 | **Cons:**
118 |
119 | - The API might be slightly different from Moment.js, which could require some adjustments if migrating from Moment.js.
120 | - Less popular compared to Moment.js (although popularity has been growing steadily).
121 |
122 | GitHub Repository: https://github.com/date-fns/date-fns
123 | Official Website: https://date-fns.org/
124 |
125 | ---
126 |
127 | ### Luxon
128 |
129 | **Luxon** is a powerful and modern date manipulation library with excellent internationalization and time zone support. It has been gaining popularity as a suitable alternative to Moment.js due to its modern features, performance improvements, and active development.
130 |
131 | **Pros:**
132 |
133 | - Modern and robust library developed by the creators of Moment.js.
134 | - Immutable design for predictable date operations.
135 | - Comprehensive API for parsing, formatting, manipulating, and working with time zones.
136 | - Excellent internationalization (i18n) support.
137 | - Effective time zone handling using the IANA Time Zone Database.
138 | - Active development and maintenance.
139 | - Good performance.
140 |
141 | **Cons:**
142 |
143 | - Smaller community compared to Date-fns.
144 | - Slightly larger bundle size compared to some other lightweight alternatives.
145 |
146 | GitHub Repository: https://github.com/moment/luxon
147 | Official Website: https://moment.github.io/luxon/
148 |
149 | ---
150 |
151 | ### Day.js
152 |
153 | **day.js** is another popular and lightweight JavaScript library for date and time manipulation. It is inspired by Moment.js but aims to be a modern and minimalist alternative with a similar API and functionality.
154 |
155 | **Pros:**
156 |
157 | - Lightweight and small bundle size, similar to date-fns.
158 | - API is inspired by Moment.js, making it easy for developers familiar with Moment.js to transition to Day.js.
159 | - Supports internationalization and has localization options.
160 | - Actively developed and maintained.
161 |
162 | **Cons:**
163 |
164 | - Smaller community compared to date-fns.
165 | - Might not have all the same features and functionalities as Moment.js, which could be a concern for projects that rely heavily on specific Moment.js features.
166 |
167 | GitHub Repository: https://github.com/iamkun/dayjs
168 | Official Website: https://day.js.org/
169 |
170 | ## Summary
171 |
172 | In summary, the choice among these libraries depends on your project's specific needs and priorities:
173 |
174 | - If you need a modern and robust library with excellent internationalization and time zone support, **Luxon** might be a great choice, especially for projects that require precise time zone handling and have more tolerance for a slightly larger bundle size.
175 | - If you want a lightweight alternative with an API inspired by Moment.js and prefer a smaller bundle size, **Day.js** is a suitable option, especially if you are transitioning from Moment.js or working on projects that prioritize smaller bundle sizes.
176 | - If your project needs a lightweight and popular option with a functional programming approach and good TypeScript support, **Date-fns** is a strong contender, particularly for projects that emphasize bundle size optimization and adherence to modern JavaScript practices.
177 |
--------------------------------------------------------------------------------
/ui-components/otp-input.md:
--------------------------------------------------------------------------------
1 | # OTP Input Component
2 |
3 | 1. [General information](#general-info)
4 | 2. [Setup](#setup)
5 | 3. [Usage](#usage)
6 |
7 | ## General information
8 |
9 | An OTP input, also known as One-Time Password input, is a security mechanism used to enhance the authentication process in various online services and applications. It is a temporary and single-use code that is valid for a short period of time, typically just a few minutes. The primary purpose of OTPs is to add an extra layer of security on top of traditional username and password-based authentication methods.
10 |
11 | It could look like this component below:
12 | 
13 |
14 | ## Setup
15 |
16 | In the example below we use [react-otp-input](https://www.npmjs.com/package/react-otp-input) library for configuring this input.
17 | Install this package to your app:
18 |
19 | ```bash
20 | pnpm install react-otp-input
21 | # or
22 | yarn add react-otp-input
23 | ```
24 |
25 | ## Usage
26 |
27 | ```typescript
28 | // OTPInput.tsx
29 |
30 | import { FormHelperText, styled } from '@mui/material';
31 | import { FC, useState } from 'react';
32 | import OtpInput from 'react-otp-input';
33 |
34 | interface IProps {
35 | error: string;
36 | }
37 |
38 | // TODO: styles could be redefined here
39 | const StyledInput = styled('input')(({ theme }) => ({
40 | height: '57px',
41 | width: '57px',
42 | borderRadius: '3.5px',
43 | backgroundColor: 'rgba(255, 255, 255, 0.16)',
44 | color: theme.palette.common.white,
45 | fontSize: '24px',
46 | fontWeight: 700,
47 | marginRight: theme.spacing(2),
48 | border: '2px solid transparent',
49 | '&:last-child': {
50 | marginRight: 0,
51 | },
52 | '&:focus, &:focus-visible': {
53 | borderColor: theme.palette.secondary.main,
54 | outline: 'none',
55 | },
56 | '&.error': {
57 | borderColor: theme.palette.error.main,
58 | '&:focus, &:focus-visible': {
59 | borderColor: theme.palette.error.main,
60 | },
61 | },
62 | }));
63 |
64 | export const OTPInput: FC = ({ error }) => {
65 | const [code, setCode] = useState('');
66 |
67 | return (
68 | <>
69 | (
75 |
80 | )}
81 | />
82 | {error && Code is not valid}
83 | >
84 | );
85 | };
86 | ```
87 |
--------------------------------------------------------------------------------
/ui-components/simple-dialog.md:
--------------------------------------------------------------------------------
1 | # Simple dialog system
2 |
3 | ## What is it?
4 |
5 | This code sets up a reusable "danger modal" component that can be used to display a styled modal dialog with buttons for resolving or rejecting an action. The danger function creates and manages the rendering of this modal based on the provided configuration and user interactions.
6 |
7 | ## Example
8 |
9 | ```typescript
10 | import styled from "@emotion/styled";
11 | import { Box, Button, Modal, Stack, Typography } from "@mui/material";
12 | import { ThemeProvider as MuiThemeProvider } from "@mui/material/styles";
13 | import { FC } from "react";
14 | import { createRoot } from "react-dom/client";
15 |
16 | import { theme } from "~/styles/theme";
17 |
18 | // This line selects an HTML element with the id 'modal' and assigns it to the modalRoot constant. This element is where the modal will be rendered.
19 | const modalRoot = document.getElementById("modal");
20 |
21 | interface Config {
22 | title: string;
23 | description: string;
24 | actionButtonName: string;
25 | }
26 |
27 | interface DangerModalProps extends Config {
28 | resolve: () => void;
29 | reject: () => void;
30 | }
31 |
32 | const StyledModal = styled(Modal)`
33 | border-radius: 8px;
34 | width: 320px;
35 | height: fit-content;
36 | margin: auto;
37 | overflow: hidden;
38 | `;
39 |
40 | // example of modal
41 | const DangerModal: FC = ({
42 | resolve,
43 | reject,
44 | title,
45 | description,
46 | actionButtonName = "Ok",
47 | }) => (
48 |
49 |
50 |
51 | {title}
52 |
53 |
54 | {description}
55 |
56 |
57 |
60 |
63 |
64 |
65 |
66 | );
67 |
68 | // This exports a function called danger that takes a config object as its parameter.
69 | // This function creates a new Promise that will resolve or reject based on user interaction with the modal.
70 | // Inside the Promise, it renders the DangerModal component with the provided configuration and attaches it to the modalRoot.
71 | // When the user interacts with the modal, it calls resolve or reject accordingly and unmounts the modal.
72 | export const danger = (config: Config) => {
73 | return new Promise((resolve, reject) => {
74 | const root = createRoot(modalRoot);
75 |
76 | root.render(
77 | // need to add theme provider because render of this modal outside main app
78 |
79 | {
82 | resolve("success");
83 | root.unmount();
84 | }}
85 | reject={() => {
86 | reject("failure");
87 | root.unmount();
88 | }}
89 | />
90 |
91 | );
92 | });
93 | };
94 | ```
95 |
96 | ## Pros
97 |
98 | 1. Reusability:
99 |
100 | - The DangerModal component is reusable and can be easily integrated into different parts of the application wherever a confirmation or danger modal is needed.
101 | - The danger function provides a convenient way to display the modal with customizable configurations.
102 |
103 | 2. Styling:
104 |
105 | - The use of Emotion for styling (StyledModal) allows for a flexible and easily maintainable styling approach within the component.
106 |
107 | 3. Separation of Concerns:
108 |
109 | - The separation of concerns is maintained by keeping the modal logic and presentation encapsulated within the DangerModal component.
110 |
111 | 4. Promise-Based Interaction:
112 |
113 | - The use of promises (new Promise(...)) in the danger function allows for easy handling of asynchronous interactions. The promise is resolved or rejected based on user actions.
114 |
115 | 5. Dynamic Rendering:
116 |
117 | - The modal is dynamically rendered using React's createRoot and can be mounted on a specific DOM element (modalRoot), providing flexibility in where the modal is rendered within the DOM.
118 |
119 | ## Cons
120 |
121 | 1. Global DOM Dependency:
122 |
123 | - The reliance on document.getElementById('modal') to find the modal root assumes that there is an HTML element with the ID 'modal' in the global DOM. This might lead to issues in a more complex or dynamically changing DOM structure.
124 |
125 | 2. Limited Configuration:
126 |
127 | - The current configuration (Config interface) is minimal, only allowing customization of the modal title. If more advanced configurations or variations of the modal are needed, the system may need enhancements.
128 |
129 | 3. Unmounting Entire React Tree:
130 |
131 | - The root.unmount() method is used to unmount the entire React tree, which might have unintended consequences if other components are rendered in the same root. This approach assumes that the modal is the only content in the specified root.
132 |
133 | 4. Blocking Promise Chain:
134 |
135 | - The current design blocks the execution of the code until the user interacts with the modal. In some scenarios, this might be undesirable, especially in UIs where asynchronous operations should continue while awaiting user input.
136 |
137 | ## Usage
138 |
139 | ```typescript
140 | // usage of dialog system
141 |
142 | interface config = {
143 | title?: string | ReactNode | JSX, default: ''
144 | description?: string | ReactNode | JSX, default: ''
145 | actionButtonName?: string, default: 'Start' (for info modal) | 'Delete' (for danger modal)
146 | }
147 |
148 | // run this code in any place of your project (only client side)
149 | danger(config).then(() => {
150 | // run success code (can be ignored)
151 | }).catch(() => {
152 | // run failure code (can be ignored)
153 | })
154 |
155 |
156 | // EXAMPLE WITH CUSTOM HOOK
157 | export const useCustomHook = () => {
158 | const handleDangerAction = async () => {
159 | try {
160 | await danger(config);
161 |
162 | // run success code
163 | } catch {
164 | // run cancel code or ignore it
165 | }
166 | };
167 |
168 | return {
169 | handleDangerAction,
170 | };
171 | };
172 | ```
173 |
--------------------------------------------------------------------------------
/ui-components/textarea-with-emoji.md:
--------------------------------------------------------------------------------
1 | # Textarea with Emoji picker Component
2 |
3 | 1. [General information](#general-info)
4 | 2. [Setup](#setup)
5 | 3. [Usage](#usage)
6 |
7 | ## General information
8 |
9 | An emoji picker component is a user interface element that allows users to select emojis from a list or grid of available options. It's a popular feature in modern applications, messaging platforms, and social media websites, as emojis have become an essential part of online communication, adding emotion and expression to messages.
10 |
11 | The emoji picker typically appears as a small window or popup that contains a collection of emojis categorized into various groups like smileys and people, animals and nature, food and drink, etc. Users can scroll through the list or use search functionality to find the desired emoji and click or tap on it to insert it into the text input field, comment section, or wherever they need it.
12 |
13 | It could look like this component below:
14 | 
15 |
16 | ## Setup
17 |
18 | In the example below we use [@emoji-mart/react](https://github.com/missive/emoji-mart) library.
19 | Install this package to your app:
20 |
21 | ```bash
22 | pnpm install @emoji-mart/data @emoji-mart/react
23 | # or
24 | yarn add @emoji-mart/data @emoji-mart/react
25 | ```
26 |
27 | ## Usage
28 |
29 | ```typescript
30 | // useModal.ts hook
31 |
32 | import { useState, useCallback } from "react";
33 |
34 | export const useModal = () => {
35 | const [showModal, setShowModal] = useState(false);
36 | const [payload, setPayload] = useState(null);
37 |
38 | const onOpen = useCallback(() => {
39 | setShowModal(true);
40 | }, [setShowModal]);
41 |
42 | const onClose = useCallback(() => {
43 | setPayload(null);
44 | setShowModal(false);
45 | }, [setShowModal]);
46 |
47 | return {
48 | showModal,
49 | onOpen,
50 | onClose,
51 | payload,
52 | setPayload,
53 | };
54 | };
55 |
56 | // styles.ts
57 | import { styled } from "@mui/material/styles";
58 | import { Box } from "@mui/material";
59 |
60 | export const Wrap = styled(Box)(() => ({
61 | "& .link-wrapper": {
62 | marginTop: "8px !important",
63 | "& > a": {
64 | color: "#326164",
65 | display: "inline-block",
66 | textDecoration: "none",
67 |
68 | "& > svg": {
69 | verticalAlign: "middle",
70 | },
71 |
72 | "& > p": {
73 | color: "#326164",
74 | display: "inline-block",
75 | lineHeight: "12px",
76 | marginLeft: "6px",
77 | verticalAlign: "middle",
78 | },
79 | },
80 | },
81 |
82 | "& .picker-wrapper": {
83 | position: "relative",
84 | marginTop: "0 !important",
85 | zIndex: 6,
86 | "& > div": {
87 | position: "absolute",
88 | top: 0,
89 | left: 0,
90 | zIndex: 2,
91 | },
92 | },
93 | }));
94 |
95 | // Note! The Textarea component you can use from our template here: https://github.com/uptechteam/fe-vitejs-template/tree/develop/src/components/atoms/ControlledFields/Textarea
96 |
97 | // TextareaWithEmojis.tsx
98 |
99 | import { useCallback } from "react";
100 | import Picker from "@emoji-mart/react";
101 | import emojiPickerData from "@emoji-mart/data";
102 | import { Box, Typography } from "@mui/material";
103 |
104 | import { useModal } from "@hooks";
105 | import { Textarea } from "@atoms";
106 | import { ReactComponent as EmojisIcon } from "@assets/svgs/Emojis.svg";
107 | import { Wrap } from "./styles";
108 |
109 | const id = "someBlockId"; // It could be updated to another one
110 |
111 | export interface IProps {
112 | name: Path;
113 | setValue: UseFormSetValue;
114 | control: Control;
115 | }
116 |
117 | export const TextareaWithEmojis = ({
118 | name,
119 | setValue,
120 | control
121 | }: IProps) => {
122 | const {
123 | showModal: isShowingEmojis,
124 | onOpen: showEmojis,
125 | onClose: hideEmojis,
126 | } = useModal();
127 |
128 | const handleEmojiSelect = useCallback((emojiObject) => {
129 | const textAreaElement = document.getElementById(id);
130 |
131 | if (textAreaElement) {
132 | const newValue =
133 | textAreaElement.value.substr(0, textAreaElement.selectionStart) +
134 | emojiObject.native +
135 | textAreaElement.value.substr(textAreaElement.selectionEnd);
136 |
137 | setValue(name, newValue);
138 | }
139 | }, []);
140 |
141 | const handleClickOutside = useCallback(() => {
142 | hideEmojis();
143 | }, []);
144 |
145 | const handleEmojisClick = useCallback(
146 | (event) => {
147 | event.preventDefault();
148 | event.stopPropagation();
149 |
150 | if (isShowingEmojis) {
151 | hideEmojis();
152 | } else {
153 | showEmojis();
154 | }
155 | },
156 | [isShowingEmojis]
157 | );
158 |
159 | return (
160 |
161 |
162 |
163 |
164 |
165 | Emoji
166 |
167 |
168 |
172 |
178 |
179 |
180 | );
181 | };
182 | ```
183 |
--------------------------------------------------------------------------------
/ui-components/tree-select.md:
--------------------------------------------------------------------------------
1 | # Tree view multi-select component
2 |
3 | 1. [General information](#general-info)
4 | 2. [Setup](#setup)
5 | 3. [Usage](#usage)
6 |
7 | ## General information
8 |
9 | It's a select component that can display hierarchical tree data.
10 |
11 | It could look like this component below:
12 | 
13 |
14 | ## Setup
15 |
16 | In the example below we use [react-dropdown-tree-select](https://dowjones.github.io/react-dropdown-tree-select/#/story/readme) library for configuring this component.
17 | Also, we need to install the `lodash.isequal` package for coparing objects inside this component.
18 | So install thesese packages to your app:
19 |
20 | ```bash
21 | pnpm install react-dropdown-tree-select lodash.isequal
22 | ```
23 |
24 | ## Usage
25 |
26 | Here is a [demo](https://codesandbox.io/p/sandbox/mutable-water-6z2yqc) of this component in CodeSandbox.
27 | We use react-hook-form and MUI here.
28 |
29 | ```typescript
30 | // Input data sample:
31 |
32 | const placesOptions = [
33 | {
34 | label: 'Germany',
35 | value: 'Germany',
36 | children: [
37 | {
38 | label: 'Berlin',
39 | value: 'Berlin',
40 | parent: 'Germany',
41 | checked: false,
42 | },
43 | {
44 | label: 'Dusseldorf',
45 | value: 'Dusseldorf',
46 | parent: 'Germany',
47 | checked: false,
48 | },
49 | ],
50 | checked: false,
51 | },
52 | {
53 | label: 'Great Britain',
54 | value: 'Great Britain',
55 | children: [
56 | {
57 | label: 'London',
58 | value: 'London',
59 | parent: 'Great Britain',
60 | checked: false,
61 | },
62 | ],
63 | checked: false,
64 | },
65 | {
66 | label: 'HiddenCountry',
67 | value: 'HiddenCountry',
68 | children: [
69 | {
70 | label: 'Test',
71 | value: 'Test',
72 | parent: 'HiddenCountry',
73 | checked: false,
74 | },
75 | ],
76 | checked: false,
77 | },
78 | {
79 | label: 'Israel',
80 | value: 'Israel',
81 | children: [
82 | {
83 | label: 'Haifa',
84 | value: 'Haifa',
85 | parent: 'Israel',
86 | checked: false,
87 | },
88 | {
89 | label: 'Kiryat Ono',
90 | value: 'Kiryat Ono',
91 | parent: 'Israel',
92 | checked: false,
93 | },
94 | {
95 | label: 'Petach Tikva',
96 | value: 'Petach Tikva',
97 | parent: 'Israel',
98 | checked: false,
99 | },
100 | {
101 | label: 'Raanana',
102 | value: 'Raanana',
103 | parent: 'Israel',
104 | checked: false,
105 | },
106 | {
107 | label: 'Ramat Gan',
108 | value: 'Ramat Gan',
109 | parent: 'Israel',
110 | checked: false,
111 | },
112 | {
113 | label: 'Tel Aviv',
114 | value: 'Tel Aviv',
115 | parent: 'Israel',
116 | checked: false,
117 | },
118 | ],
119 | checked: false,
120 | },
121 | {
122 | label: 'Netherlands',
123 | value: 'Netherlands',
124 | children: [
125 | {
126 | label: 'Amsterdam',
127 | value: 'Amsterdam',
128 | parent: 'Netherlands',
129 | checked: false,
130 | },
131 | {
132 | label: 'Utrecht',
133 | value: 'Utrecht',
134 | parent: 'Netherlands',
135 | checked: false,
136 | },
137 | {
138 | label: 'UTRECHT',
139 | value: 'UTRECHT',
140 | parent: 'Netherlands',
141 | checked: false,
142 | },
143 | ],
144 | checked: false,
145 | },
146 | {
147 | label: 'Poland',
148 | value: 'Poland',
149 | children: [
150 | {
151 | label: 'Warsaw',
152 | value: 'Warsaw',
153 | parent: 'Poland',
154 | checked: false,
155 | },
156 | ],
157 | checked: false,
158 | },
159 | {
160 | label: 'UK',
161 | value: 'UK',
162 | children: [
163 | {
164 | label: 'London',
165 | value: 'London',
166 | parent: 'UK',
167 | checked: false,
168 | },
169 | ],
170 | checked: false,
171 | },
172 | {
173 | label: 'Ukraine',
174 | value: 'Ukraine',
175 | children: [
176 | {
177 | label: 'Kyiv',
178 | value: 'Kyiv',
179 | parent: 'Ukraine',
180 | checked: false,
181 | },
182 | ],
183 | checked: false,
184 | },
185 | {
186 | label: 'US',
187 | value: 'US',
188 | children: [
189 | {
190 | label: 'DC',
191 | value: 'DC',
192 | parent: 'US',
193 | checked: false,
194 | },
195 | {
196 | label: 'Miami',
197 | value: 'Miami',
198 | parent: 'US',
199 | checked: false,
200 | },
201 | {
202 | label: 'Philadelphia',
203 | value: 'Philadelphia',
204 | parent: 'US',
205 | checked: false,
206 | },
207 | ],
208 | checked: false,
209 | },
210 | {
211 | label: 'USA',
212 | value: 'USA',
213 | children: [
214 | {
215 | label: 'Miami',
216 | value: 'Miami',
217 | parent: 'USA',
218 | checked: false,
219 | },
220 | {
221 | label: 'WASHINGTON, DC',
222 | value: 'WASHINGTON, DC',
223 | parent: 'USA',
224 | checked: false,
225 | },
226 | ],
227 | checked: false,
228 | },
229 | ];
230 |
231 | ```
232 |
233 | ## Improvements
234 |
235 | This component based on the react-dropdown-tree-select library which uses an old version of React (v16) under the hood. It could cause issues with the support of this component in the future.
236 |
--------------------------------------------------------------------------------