├── README.md
├── day1-form-validation
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── components
│ ├── Forms.js
│ ├── constants.js
│ ├── form.css
│ └── validate.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ ├── reportWebVitals.js
│ └── setupTests.js
├── day2-drag-and-drop
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── Column.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ ├── reportWebVitals.js
│ └── setupTests.js
├── day3-progressive-web-app
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── cropped.png
│ ├── index.html
│ ├── manifest.json
│ ├── offline.html
│ ├── robots.txt
│ └── serviceWorker.js
└── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── Column.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ ├── reportWebVitals.js
│ └── setupTests.js
├── day4-browser-encryption
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ ├── reportWebVitals.js
│ ├── setupTests.js
│ └── utils
│ ├── encryption.js
│ └── localstorage.js
├── day5-microfrontend
├── README.md
├── form
│ ├── README.md
│ ├── config-overrides.js
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ └── robots.txt
│ ├── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── App.test.js
│ │ ├── Form.js
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── logo.svg
│ │ ├── reportWebVitals.js
│ │ ├── setupProxy.js
│ │ ├── setupTests.js
│ │ └── utils.js
│ └── yarn.lock
├── host1
│ ├── README.md
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ └── robots.txt
│ ├── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── App.test.js
│ │ ├── MicroFrontend.js
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── logo.svg
│ │ ├── reportWebVitals.js
│ │ └── setupTests.js
│ └── yarn.lock
└── host2
│ ├── README.md
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
│ ├── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── MicroFrontend.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ ├── reportWebVitals.js
│ └── setupTests.js
│ └── yarn.lock
├── day6-price-drop-alert
├── README.md
├── package-lock.json
├── package.json
└── server.js
└── day7-folder-file-structure-like-vs-code
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
└── src
├── App.css
├── App.js
├── App.test.js
├── FileTree.js
├── Folder.js
├── index.css
├── index.js
├── logo.svg
├── reportWebVitals.js
├── setupTests.js
└── utils.js
/README.md:
--------------------------------------------------------------------------------
1 | Here is the text with all the numbers removed:
2 |
3 | ---
4 |
5 | Connect at Instagram: [@codewithayaan](https://www.instagram.com/_codewithayaan/)
6 |
7 | Source Videos: [Youtube | Playlist](https://www.youtube.com/watch?v=W3oxPPuIOfw&list=PLe5vjs4_PbIJLznsDNc0MyFcuY5DyySao)
8 |
9 | # Machine Round 🧠 Challenge 🎯
10 |
11 | - [X] **Form Validation**: Implement client-side form validation for a registration form using HTML5 and JavaScript. Validate fields like email, password strength, and required fields. [CODE LINK](https://github.com/codewithayaann/Machine-Round-Challenge/tree/main/day1-form-validation)
12 |
13 | - [X] **Implement a Drag and Drop Feature**: Create a web page with a drag-and-drop interface using HTML, CSS, and JavaScript and ReactJS. Allow users to drag elements and drop them into designated areas. [CODE LINK](https://github.com/codewithayaann/Machine-Round-Challenge/tree/main/day2-drag-and-drop)
14 |
15 | - [X] **Progressive Web App (PWA)**: Convert a web application into a Progressive Web App. [CODE LINK](https://github.com/codewithayaann/Machine-Round-Challenge/tree/main/day3-progressive-web-app)
16 |
17 | - [X] **Browser Storage Encryption**: Implement encryption for data stored in browser storage (e.g., localStorage) to enhance security. [CODE LINK](https://github.com/codewithayaann/Machine-Round-Challenge/tree/main/day4-browser-encryption)
18 | - [X] **Microservice in Frontend**: Implement microservice in frontend (Microfrontend) and connect that to other app. [CODE LINK](https://github.com/codewithayaann/Machine-Round-Challenge/tree/main/day5-microfrontend)
19 |
20 | - [X] **Web Scraping using Node JS**: Scrap flipkart product price and create price drop alert application. [CODE LINK](https://github.com/codewithayaann/Machine-Round-Challenge/tree/main/day5-microfrontend)
21 |
22 | - [X] **Design a File Explorer structure like VSCode** : [CODE LINK](https://github.com/codewithayaann/Machine-Round-Challenge/tree/main/day7-folder-file-structure-like-vs-code)
23 |
24 | - **Infinite Scroll**: Implement an infinite scroll feature on a web page. Load additional content as the user scrolls down the page using ReactJS.
25 |
26 | - **Form Autocomplete**: Add autocomplete functionality to a search input field using React. Provide suggestions as the user types.
27 |
28 | - **Interactive Map**: Build an interactive map using a mapping library (e.g., Leaflet, Google Maps API) and allow users to search for locations, add markers, and display additional information when clicking on markers.
29 |
30 | - **Web Accessibility**: Ensure that a web page complies with web accessibility standards (WCAG). Make necessary HTML and CSS modifications to improve accessibility for users with disabilities.
31 |
32 | - **CSS Animation**: Create a CSS animation, such as a spinning loader or a fading effect, to enhance user experience on a webpage.
33 |
34 | - **Responsive Email Template**: Design and code a responsive email template that looks good on both desktop and mobile email clients.
35 |
36 | - **Dynamic Content Filtering**: Create a web page that allows users to filter content dynamically based on categories or tags using JavaScript.
37 |
38 | ## Intermediate Frontend Development
39 |
40 | - **Real-time Chat Application**: Build a real-time chat application using a frontend framework (e.g., React, Vue.js) and a backend technology like WebSocket or Firebase.
41 |
42 | - **Data Visualization**: Create a data visualization chart (e.g., bar chart, pie chart) using a JavaScript library like D3.js or Chart.js.
43 |
44 | - **Sticky Navigation**: Implement a sticky navigation bar that sticks to the top of the page when scrolling down and returns to its original position when scrolling up.
45 |
46 | - **Unit Testing**: Write unit tests for a JavaScript function or component using a testing framework like Jest.
47 |
48 | - **Cross-browser Compatibility**: Ensure that a webpage works correctly and looks consistent across different web browsers (e.g., Chrome, Firefox, Edge).
49 |
50 | - **Email Signature**: Design and code a responsive email signature that can be used in email clients.
51 |
52 | - **Infinite Carousel**: Create an infinite carousel/slider that automatically loops through a set of images or content, providing navigation controls for the user.
53 |
54 | - **Tooltip Component**: Design and implement a reusable tooltip component in HTML, CSS, and React.js, that appears when hovering over specific elements.
55 |
56 | - **Custom Dropdown Menu**: Create a custom dropdown menu that expands and collapses with smooth animations when the user hovers over a trigger element.
57 |
58 | - **Interactive Forms**: Enhance a web form with interactive features like auto-suggestions, input validation, and conditional form fields using JavaScript.
59 |
60 | - **Page Transitions**: Implement smooth page transitions between different sections or pages of a website using CSS transitions and JavaScript.
61 |
62 | - **Keyboard Shortcuts**: Add keyboard shortcuts to a web application to improve user accessibility and navigation.
63 |
64 | - **Dark Mode Toggle**: Create a dark mode toggle button that switches the website's color scheme between light and dark mode.
65 |
66 | - **WebGL Experiment**: Develop an interactive WebGL project, such as a 3D visualization or animation, and embed it into a webpage.
67 |
68 | - **Custom Video Player**: Build a custom HTML5 video player with custom controls, such as play, pause, volume, and progress bar.
69 |
70 | - **Page Printing Styles**: Define CSS styles for printing a web page so that it looks well-formatted when printed on paper.
71 |
72 | - **Implement a Photo Gallery**: Create a photo gallery with albums, thumbnails, and the ability to view images in a larger size.
73 |
74 | - **Web Audio Player**: Build a web-based audio player with features like play, pause, volume control, and playlist support.
75 |
76 | - **Augmented Reality Web App**: Develop an augmented reality (AR) web application that overlays digital content on the user's real-world view using WebXR or similar technology.
77 |
78 | - **Progressive Image Loading Placeholder**: Implement a progressive image loading technique that displays a blurred or low-quality image as a placeholder while the high-quality image loads.
79 |
80 | - **Automated Web Testing**: Write automated tests for a web application using testing frameworks like Selenium or Cypress.
81 |
82 | ## Expert Frontend Development
83 |
84 | - **Custom Web Animation Library**: Create a small JavaScript library for animating elements on a webpage, including support for various easing functions.
85 |
86 | - **Offline Support**: Implement offline support for a web application, allowing users to access content even when they have no internet connection.
87 |
88 | - **Server-Side Rendering (SSR) with React**: Set up server-side rendering (SSR) for a React application.
89 |
90 | - **Virtual DOM Implementation**: Implement a simplified virtual DOM (similar to React's virtual DOM) in JavaScript.
91 |
92 | - **Touch and Gesture Events**: Implement touch and gesture events in a web application to provide touch-based interactions on mobile devices.
93 |
94 | - **Browser Storage Management**: Build a utility for managing browser storage (localStorage, sessionStorage) and provide methods for setting, getting, and removing data.
95 |
96 | - **Web Worker**: Use a web worker to offload computationally intensive tasks from the main thread, improving performance.
97 |
98 | - **Component Lifecycle**: Utilize component lifecycle methods (e.g., componentDidMount, componentDidUpdate) in a React component.
99 |
100 | - **Context API**: Use React's Context API to manage and share state or data across multiple components.
101 |
102 | - **Redux Setup**: Set up a Redux store, actions, and reducers in a React application.
103 |
104 | - **Redux Middleware**: Use Redux middleware (e.g., Thunk) to handle asynchronous actions in a Redux-powered React application.
105 |
106 | - **Authentication Flow**: Implement user authentication and authorization in a React application, including login and protected routes.
107 |
108 | - **React Higher-Order Components (HOCs)**: Create a higher-order component (HOC) to add functionality to existing React components.
109 |
110 | - **Error Handling**: Implement error handling and display error messages in a React application.
111 |
112 | - **Internationalization (i18n)**: Implement internationalization and localization in a React application.
113 |
114 | - **React Animation**: Add animations and transitions to React components using libraries like React Spring or Framer Motion.
115 |
116 | - **Data Pagination**: Implement data pagination in a React application, fetching and displaying data in chunks.
117 |
118 | - **Custom React Router**: Build a custom router using React Router's low-level APIs to gain a deeper understanding of routing.
119 |
120 | ## Redux
121 |
122 | - **Redux Immutable State**: Ensure that the Redux store's state remains immutable to prevent unintended mutations.
123 |
124 | - **Redux Persistence**: Implement state persistence in a Redux application, allowing the state to be saved and restored across sessions.
125 |
126 | - **Redux DevTools**: Integrate and use Redux DevTools to inspect and debug the Redux store.
127 |
--------------------------------------------------------------------------------
/day1-form-validation/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/day1-form-validation/README.md:
--------------------------------------------------------------------------------
1 | # React Dynamic Forms with Validation
2 |
3 | YT Video : https://youtu.be/-P_uKkxYe4Q?si=guPwfrX3nEIyprfM
4 |
5 | This component allows you to create dynamic forms with customizable validation using a schema-based approach in React.
6 |
7 | ## Features
8 |
9 | - Dynamic form generation from a schema.
10 | - Validation for required fields, length, patterns, password strength, and matching fields.
11 | - Event-driven validation (on `blur` or `change`).
12 |
13 | ## Usage
14 |
15 | ### 1. Define Your Form Schema
16 |
17 | Create a form schema that outlines the fields and their validation rules.
18 |
19 | ```javascript
20 |
21 | export const validationSchema = {
22 | name: {
23 | required: true,
24 | minLength: 2,
25 | maxLength: 50,
26 | pattern: /^[a-zA-Z ]+$/,
27 | },
28 | email: {
29 | required: true,
30 | pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
31 | },
32 | password: {
33 | required: true,
34 | minLength: 8,
35 | strength: {
36 | uppercase: 1,
37 | lowercase: 1,
38 | digit: 1,
39 | special: 1,
40 | },
41 | },
42 | confirmPassword: {
43 | required: true,
44 | match: "password",
45 | },
46 | };
47 | ```
48 |
49 |
50 |
51 | ```javascript
52 | export const FORM = [
53 | { id: 'name', label: 'Name', name: 'name' },
54 | { id: 'email', label: 'Email', name: 'email', type: 'email' },
55 | { id: 'password', label: 'Password', name: 'password', type: 'password' },
56 | { id: 'confirmPassword', label: 'Confirm Password', name: 'confirmPassword', type: 'password' }
57 | ];
58 | ```
59 |
60 | ### 3. Forms Component
61 |
62 | ```javascript
63 | import React, { useState } from 'react';
64 | import "./form.css";
65 | import { validateForm } from './validate';
66 |
67 | export const Forms = ({ forms, schema, validateOn }) => {
68 | const [errors, setError] = useState({});
69 |
70 | const handleValidate = (form, schema) => {
71 | const errors = validateForm(form, schema);
72 | const haveErrors = !!Object.keys(errors).length;
73 | setError(errors);
74 | return haveErrors;
75 | };
76 |
77 | const handleValidateOnEvent = (event) => {
78 | if (event.type === validateOn) {
79 | const name = event.target.name;
80 | const objectData = { [name]: event.target.value };
81 | const haveErrors = handleValidate(objectData, { [name]: schema[name] });
82 | if (haveErrors) return;
83 | }
84 | };
85 |
86 | const onSubmit = (event) => {
87 | event.preventDefault();
88 | const formData = new FormData(event.target);
89 | const obj = Object.fromEntries(formData);
90 | const haveErrors = handleValidate(obj, schema);
91 | if (haveErrors) return;
92 | alert("Hurray!! API HIT for save");
93 | };
94 |
95 | return (
96 |
113 | );
114 | };
115 | ```
116 |
117 | ### 4. Application Usage
118 |
119 | ```javascript
120 | import React from 'react';
121 | import { Forms } from './Forms';
122 | import { validationSchema } from './validate';
123 |
124 | const FORM = [
125 | { id: 'name', label: 'Name', name: 'name' },
126 | { id: 'email', label: 'Email', name: 'email', type: 'email' },
127 | { id: 'password', label: 'Password', name: 'password', type: 'password' },
128 | { id: 'confirmPassword', label: 'Confirm Password', name: 'confirmPassword', type: 'password' }
129 | ];
130 |
131 | const App = () => (
132 |
133 | );
134 |
135 | export default App;
136 | ```
137 |
138 |
139 |
--------------------------------------------------------------------------------
/day1-form-validation/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "day1-form-validation",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.17.0",
7 | "@testing-library/react": "^13.4.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "react": "^18.3.1",
10 | "react-dom": "^18.3.1",
11 | "react-scripts": "5.0.1",
12 | "web-vitals": "^2.1.4"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test",
18 | "eject": "react-scripts eject"
19 | },
20 | "eslintConfig": {
21 | "extends": [
22 | "react-app",
23 | "react-app/jest"
24 | ]
25 | },
26 | "browserslist": {
27 | "production": [
28 | ">0.2%",
29 | "not dead",
30 | "not op_mini all"
31 | ],
32 | "development": [
33 | "last 1 chrome version",
34 | "last 1 firefox version",
35 | "last 1 safari version"
36 | ]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/day1-form-validation/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day1-form-validation/public/favicon.ico
--------------------------------------------------------------------------------
/day1-form-validation/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 | You need to enable JavaScript to run this app.
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/day1-form-validation/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day1-form-validation/public/logo192.png
--------------------------------------------------------------------------------
/day1-form-validation/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day1-form-validation/public/logo512.png
--------------------------------------------------------------------------------
/day1-form-validation/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/day1-form-validation/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/day1-form-validation/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | @media (prefers-reduced-motion: no-preference) {
11 | .App-logo {
12 | animation: App-logo-spin infinite 20s linear;
13 | }
14 | }
15 |
16 | .App-header {
17 | background-color: #282c34;
18 | min-height: 100vh;
19 | display: flex;
20 | flex-direction: column;
21 | align-items: center;
22 | justify-content: center;
23 | font-size: calc(10px + 2vmin);
24 | color: white;
25 | }
26 |
27 | .App-link {
28 | color: #61dafb;
29 | }
30 |
31 | @keyframes App-logo-spin {
32 | from {
33 | transform: rotate(0deg);
34 | }
35 | to {
36 | transform: rotate(360deg);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/day1-form-validation/src/App.js:
--------------------------------------------------------------------------------
1 | import './App.css';
2 | import { FORM } from './components/constants';
3 | import { Forms } from './components/Forms';
4 | import { validationSchema } from './components/validate';
5 |
6 | function App() {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 | );
14 | }
15 |
16 | export default App;
17 |
--------------------------------------------------------------------------------
/day1-form-validation/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render( );
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/day1-form-validation/src/components/Forms.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import "./form.css"
3 | import { validateForm } from './validate';
4 |
5 | export const Forms = ({ forms, schema, validateOn }) => {
6 | const [errors, setError] = useState({})
7 |
8 | const handleValidate = (form, schema) => {
9 | const errors = validateForm(form, schema);
10 | const haveErrors = !!Object.keys(errors).length;
11 | setError(errors)
12 | return haveErrors;
13 | };
14 |
15 | const handleValidateOnEvent = (event) => {
16 | if (event.type === validateOn) {
17 | const name = event.target.name
18 | const objectData = {
19 | [name]: event.target.value
20 | }
21 | const haveErrors = handleValidate(objectData, {
22 | [name]: schema[name]
23 | })
24 | if (haveErrors) return;
25 | }
26 | }
27 |
28 |
29 | const onSubmit = (event) => {
30 | event.preventDefault();
31 | const formData = new FormData(event.target)
32 | const obj = Object.fromEntries(formData);
33 | const haveErrors = handleValidate(obj, schema);
34 | if (haveErrors) return;
35 | alert("Hurray!! API HIT for save");
36 |
37 | }
38 |
39 |
40 | return (
41 |
54 | )
55 | }
56 |
--------------------------------------------------------------------------------
/day1-form-validation/src/components/constants.js:
--------------------------------------------------------------------------------
1 | export const FORM = [{
2 | id: 'name',
3 | label: 'Name',
4 | name: 'name'
5 | },
6 | {
7 | id: 'email',
8 | label: 'Email',
9 | name: "email",
10 | type: 'email',
11 | },
12 | {
13 | id: 'password',
14 | label: 'Password',
15 | name: 'password',
16 | type: 'password'
17 | },
18 | {
19 | id: 'confirmPassword',
20 | label: 'Confirm Password',
21 | name: 'confirmPassword'
22 | }
23 | ]
--------------------------------------------------------------------------------
/day1-form-validation/src/components/form.css:
--------------------------------------------------------------------------------
1 | .d-flex {
2 | display: flex;
3 | }
4 |
5 | .flex-column {
6 | flex-direction: column;
7 | }
8 |
9 |
10 |
11 | .w-100 {
12 | width: 100%;
13 | }
14 |
15 | .label > span {
16 | margin-top: 5px;
17 | text-align: left;
18 | }
19 |
20 | .submit-btn {
21 | margin-top: 10px;
22 | background-color: lightblue;
23 | border: 0;
24 | outline: 0;
25 | padding: 5px 10px;
26 | }
27 |
28 | .error-red {
29 | font-size: 12px;
30 | color: red;
31 | margin-bottom: 5px;
32 | }
33 |
34 | input {
35 | border-radius: 4px;
36 | height: 20px;
37 | }
38 |
39 | input.invalid {
40 | border: 1px solid red;
41 | outline: none;
42 | }
--------------------------------------------------------------------------------
/day1-form-validation/src/components/validate.js:
--------------------------------------------------------------------------------
1 | export const validationSchema = {
2 | name: {
3 | required: true,
4 | minLength: 2,
5 | maxLength: 50,
6 | pattern: /^[a-zA-Z ]+$/,
7 | },
8 | email: {
9 | required: true,
10 | pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
11 | },
12 | password: {
13 | required: true,
14 | minLength: 8,
15 | strength: {
16 | uppercase: 1,
17 | lowercase: 1,
18 | digit: 1,
19 | special: 1,
20 | },
21 | },
22 | confirmPassword: {
23 | required: true,
24 | match: "password",
25 | },
26 | };
27 |
28 | const validatePasswordStrength = (password, strengthSchema) => {
29 | const errors = [];
30 | if (strengthSchema.uppercase && !/[A-Z]/.test(password)) {
31 | errors.push("Must contain at least one uppercase letter");
32 | }
33 | if (strengthSchema.lowercase && !/[a-z]/.test(password)) {
34 | errors.push("Must contain at least one lowercase letter");
35 | }
36 | if (strengthSchema.digit && !/\d/.test(password)) {
37 | errors.push("Must contain at least one digit");
38 | }
39 | if (
40 | strengthSchema.special &&
41 | !/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password)
42 | ) {
43 | errors.push("Must contain at least one special character");
44 | }
45 | return errors;
46 | };
47 |
48 |
49 |
50 | const validateField = (formData, fieldValue, fieldSchema) => {
51 | if (fieldSchema.required && !fieldValue) {
52 | return "This field is required";
53 | }
54 | if (fieldSchema.minLength && fieldValue.length < fieldSchema.minLength) {
55 | return `This field must be at least ${fieldSchema.minLength} characters long`;
56 | }
57 | if (fieldSchema.maxLength && fieldValue.length > fieldSchema.maxLength) {
58 | return `This field must be no more than ${fieldSchema.maxLength} characters long`;
59 | }
60 | if (fieldSchema.pattern && !fieldSchema.pattern.test(fieldValue)) {
61 | return "Invalid Format";
62 | }
63 | if (fieldSchema.strength) {
64 | return validatePasswordStrength(fieldValue, fieldSchema.strength).join(
65 | ", "
66 | );
67 | }
68 | if (fieldSchema.match) {
69 | if (formData[fieldSchema.match] !== fieldValue) {
70 | return "Passwords do not match";
71 | }
72 | }
73 | return null;
74 | };
75 |
76 |
77 |
78 | export const validateForm = (formData = {}, schema = {}) => {
79 | const errors = {};
80 | Object.keys(schema).forEach((field) => {
81 | const fieldSchema = schema[field];
82 | const fieldValue = formData[field];
83 | const error = validateField(formData, fieldValue, fieldSchema);
84 | if (error) {
85 | errors[field] = error;
86 | }
87 | });
88 | return errors;
89 | };
90 |
91 |
--------------------------------------------------------------------------------
/day1-form-validation/src/index.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day1-form-validation/src/index.css
--------------------------------------------------------------------------------
/day1-form-validation/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | const root = ReactDOM.createRoot(document.getElementById('root'));
8 | root.render(
9 |
10 |
11 |
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/day1-form-validation/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/day1-form-validation/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/day1-form-validation/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/day2-drag-and-drop/README.md:
--------------------------------------------------------------------------------
1 | # React JS Drag and Drop Without Libraries
2 |
3 | YT VIDEO : https://youtu.be/W3oxPPuIOfw?si=XDxyeQfA3-XWvZWr
4 |
5 | ## Overview
6 |
7 | This project demonstrates how to create a simple drag-and-drop interface using React.js without relying on any external libraries. We use built-in JavaScript functions and HTML properties to manage drag events and state transitions.
8 |
9 | ## Table of Contents
10 | 1. [Setup Instructions](#setup-instructions)
11 | 2. [Understanding the Code](#understanding-the-code)
12 | - [Initial State Setup](#initial-state-setup)
13 | - [Handling Drag and Drop Events](#handling-drag-and-drop-events)
14 | - [Creating New Items](#creating-new-items)
15 | - [Adding New Columns](#adding-new-columns)
16 | 3. [Use Case](#use-case)
17 |
18 | ## Setup Instructions
19 |
20 | To run this project locally, follow these steps:
21 |
22 | 1. **Clone the repository:**
23 | ```bash
24 | git clone https://github.com/your-username/react-drag-and-drop.git
25 | ```
26 |
27 | 2. **Navigate to the project directory:**
28 | ```bash
29 | cd react-drag-and-drop
30 | ```
31 |
32 | 3. **Install dependencies:**
33 | ```bash
34 | npm install
35 | ```
36 |
37 | 4. **Start the development server:**
38 | ```bash
39 | npm start
40 | ```
41 |
42 | ## Understanding the Code
43 |
44 | ### Initial State Setup
45 |
46 | We start by defining the initial state using the `useState` hook to manage the columns and their respective items.
47 |
48 | ```javascript
49 | const [columns, setColumns] = useState({
50 | column1: ['item1', 'item2'],
51 | column2: ['item3', 'item4']
52 | });
53 | ```
54 |
55 | - **columns**: An object representing multiple columns, each containing an array of items.
56 |
57 | ### Handling Drag and Drop Events
58 |
59 | The drag-and-drop functionality is managed through three key functions: `onDragStart`, `onDrop`, and `onDragOver`.
60 |
61 | #### onDragStart
62 |
63 | This function is triggered when an item is dragged. It stores the item's data and its originating column.
64 |
65 | ```javascript
66 | const onDragStart = (event, item, fromColumn) => {
67 | event.dataTransfer.setData('item', item);
68 | event.dataTransfer.setData('fromColumn', fromColumn);
69 | };
70 | ```
71 |
72 | #### onDrop
73 |
74 | This function handles dropping the item into the target column. It checks if the item is being dropped in a different column and then updates the state accordingly.
75 |
76 | ```javascript
77 | const onDrop = (event, toColumn) => {
78 | const item = event.dataTransfer.getData('item');
79 | const fromColumn = event.dataTransfer.getData('fromColumn');
80 |
81 | if (toColumn === fromColumn) return;
82 |
83 | setColumns((prev) => {
84 | const fromData = prev[fromColumn].filter((older) => older !== item);
85 | const toData = [...prev[toColumn], item];
86 | return {
87 | ...prev,
88 | [fromColumn]: fromData,
89 | [toColumn]: toData
90 | };
91 | });
92 | };
93 | ```
94 |
95 | #### onDragOver
96 |
97 | This function allows the drop by preventing the default behavior.
98 |
99 | ```javascript
100 | const onDragOver = (event) => event.preventDefault();
101 | ```
102 |
103 | ### Creating New Items
104 |
105 | You can create new items within a column using a simple form. The `onCreateNewItem` function handles the form submission, updating the column with the new item.
106 |
107 | ```javascript
108 | const onCreateNewItem = (event, column) => {
109 | event.preventDefault();
110 | const data = Object.fromEntries(new FormData(event.target));
111 | setColumns((prev) => ({
112 | ...prev,
113 | [column]: [...prev[column], data[column]]
114 | }));
115 | event.target.reset();
116 | };
117 | ```
118 |
119 | ### Adding New Columns
120 |
121 | Users can dynamically add new columns by clicking a button. The `createColumn` function generates a new column with an empty array of items.
122 |
123 | ```javascript
124 | const createColumn = () => {
125 | const totalColumns = Object.keys(columns).length;
126 | const newColumnName = `column${totalColumns + 1}`;
127 | setColumns(prev => ({
128 | ...prev,
129 | [newColumnName]: []
130 | }));
131 | };
132 | ```
133 |
134 | ## Use Case
135 |
136 | This project is a great starting point for building more complex drag-and-drop interfaces in React. Whether you're creating a Kanban board, a sortable list, or a task management app, understanding these core principles will help you implement efficient and intuitive drag-and-drop experiences.
137 |
--------------------------------------------------------------------------------
/day2-drag-and-drop/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "day2-drag-and-drop",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.17.0",
7 | "@testing-library/react": "^13.4.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "react": "^18.3.1",
10 | "react-dom": "^18.3.1",
11 | "react-scripts": "5.0.1",
12 | "web-vitals": "^2.1.4"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test",
18 | "eject": "react-scripts eject"
19 | },
20 | "eslintConfig": {
21 | "extends": [
22 | "react-app",
23 | "react-app/jest"
24 | ]
25 | },
26 | "browserslist": {
27 | "production": [
28 | ">0.2%",
29 | "not dead",
30 | "not op_mini all"
31 | ],
32 | "development": [
33 | "last 1 chrome version",
34 | "last 1 firefox version",
35 | "last 1 safari version"
36 | ]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/day2-drag-and-drop/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day2-drag-and-drop/public/favicon.ico
--------------------------------------------------------------------------------
/day2-drag-and-drop/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 | You need to enable JavaScript to run this app.
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/day2-drag-and-drop/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day2-drag-and-drop/public/logo192.png
--------------------------------------------------------------------------------
/day2-drag-and-drop/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day2-drag-and-drop/public/logo512.png
--------------------------------------------------------------------------------
/day2-drag-and-drop/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/day2-drag-and-drop/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/day2-drag-and-drop/src/App.css:
--------------------------------------------------------------------------------
1 | .board {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | padding: 20px;
6 | min-height: 100vh;
7 | background-color: #f0f0f0; /* added a light gray background */
8 | }
9 |
10 | .columns {
11 | display: flex;
12 | flex-wrap: wrap;
13 | justify-content: center;
14 | margin-top: 50px;
15 | }
16 |
17 |
18 | .column {
19 | background-color: #f7f7f7;
20 | border: 1px solid #ddd;
21 | border-radius: 5px;
22 | padding: 10px;
23 | margin: 10px;
24 | width: 250px;
25 | display: flex;
26 | flex-direction: column;
27 | justify-content: space-between;
28 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* added a subtle box shadow */
29 | }
30 |
31 | .column h2 {
32 | margin-top: 0;
33 | font-weight: bold; /* made the column title bold */
34 | }
35 |
36 | .column h2 .heading {
37 | color: lightcoral;
38 | }
39 |
40 | .column h2 .count {
41 | color: darkgray;
42 | margin-left: 10px;
43 | }
44 |
45 |
46 | .list-parent {
47 | padding: 0;
48 | }
49 |
50 | .item {
51 | list-style-type: none;
52 | background-color: #fff;
53 | padding: 10px;
54 | border: 1px solid #ddd;
55 | border-radius: 5px;
56 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
57 | margin-block: 5px;
58 | cursor: move; /* a/* added a move cursor to indicate draggability */
59 | }
60 |
61 | .item:last-child {
62 | border-bottom: none;
63 | }
64 |
65 | .new-item-input-form {
66 | margin-top: 5rem;
67 | }
68 |
69 | .new-item-input {
70 | padding: 10px;
71 | border: 1px solid #ccc;
72 | border-radius: 5px;
73 | width: 100%;
74 | box-sizing: border-box; /* added box-sizing to prevent overflow */
75 | }
76 |
77 | .add-item-btn:hover {
78 | background-color: #3e8e41;
79 | }
80 |
81 |
82 | .add-column-btn {
83 | background-color: #4CAF50;
84 | color: #fff;
85 | border: none;
86 | padding: 10px 20px;
87 | font-size: 16px;
88 | cursor: pointer;
89 | transition: background-color 0.2s; /* added a transition for the button hover effect */
90 | position: absolute;
91 | right: 20px;
92 | }
93 |
94 | .add-column-btn:hover {
95 | background-color: #3e8e41;
96 | }
97 |
98 | /* added animation for dragging and dropping */
99 | .dragging {
100 | opacity: 0.3;
101 | transform: scale(0);
102 | transition: transform 0.2s, opacity 0.2s;
103 | }
104 |
105 | .dropping {
106 | transform: scale(1.1);
107 | transition: transform 0.2s;
108 | }
--------------------------------------------------------------------------------
/day2-drag-and-drop/src/App.js:
--------------------------------------------------------------------------------
1 | import { Fragment, useState } from 'react';
2 | import { Column } from './Column';
3 | import './App.css';
4 |
5 | function App() {
6 | const [columns, setColumns] = useState({
7 | column1: ['item1', 'item2'],
8 | column2: ['item3', 'item4']
9 | });
10 |
11 | const swapItems = (fromColumn, fromIndex, toColumn, toIndex) => {
12 | const fromData = columns[fromColumn];
13 | const toData = columns[toColumn];
14 |
15 | if (fromColumn === toColumn) {
16 | [fromData[toIndex], fromData[fromIndex]] = [fromData[fromIndex], fromData[toIndex]];
17 | } else {
18 | const [item] = fromData.splice(fromIndex, 1);
19 | toData.splice(toIndex, 0, item);
20 | }
21 |
22 | setColumns((prev) => ({
23 | ...prev,
24 | [fromColumn]: fromData,
25 | [toColumn]: toData
26 | }));
27 | };
28 |
29 |
30 | const onDrop = (event, toColumn, toIndex) => {
31 | event.stopPropagation();
32 | const item = event.dataTransfer.getData('item');
33 | const fromColumn = event.dataTransfer.getData('fromColumn');
34 | const fromIndex = parseInt(event.dataTransfer.getData('fromIndex'), 10);
35 |
36 | //animation
37 | event.target.classList.add('dropping');
38 | setTimeout(() => {
39 | event.target.classList.remove('dropping');
40 | }, 200);
41 |
42 | if (typeof toIndex !== 'number') {
43 | // Drop on column, append to end and remove from original column
44 | setColumns((prev) => {
45 | const newColumns = { ...prev };
46 | newColumns[toColumn] = [...newColumns[toColumn], item];
47 | newColumns[fromColumn] = newColumns[fromColumn].filter((_, i) => i !== fromIndex);
48 | return newColumns;
49 | });
50 | } else {
51 | // swap if same column or swapping from another column
52 | swapItems(fromColumn, fromIndex, toColumn, toIndex);
53 | }
54 |
55 | };
56 |
57 | const onDragOver = (event) => {
58 | event.preventDefault();
59 | };
60 |
61 | const onDragEnd = (event) => {
62 | event.target.classList.remove('dragging');
63 | }
64 |
65 | const onDragStart = (event, item, fromColumn, fromIndex) => {
66 | event.dataTransfer.setData('item', item);
67 | event.dataTransfer.setData('fromColumn', fromColumn);
68 | event.dataTransfer.setData('fromIndex', fromIndex);
69 | event.target.classList.add('dragging');
70 | };
71 |
72 | const onCreateNewItem = (event, column) => {
73 | event.preventDefault();
74 | const data = Object.fromEntries(new FormData(event.target));
75 | setColumns((prev) => ({
76 | ...prev,
77 | [column]: [...prev[column], data[column]]
78 | }));
79 | event.target.reset();
80 | };
81 |
82 | const createColumn = () => {
83 | const totalColumns = Object.keys(columns).length;
84 | const newColumnName = `column${totalColumns + 1}`;
85 | setColumns((prev) => ({
86 | ...prev,
87 | [newColumnName]: []
88 | }));
89 | };
90 |
91 | return (
92 |
93 |
94 |
95 | {Object.keys(columns).map((column) => (
96 |
105 | ))}
106 |
107 |
108 | + Add Column
109 |
110 |
111 |
112 | );
113 | }
114 |
115 | export default App;
--------------------------------------------------------------------------------
/day2-drag-and-drop/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import "./App.css";
3 |
4 | const App = () => {
5 | const [columns, setColumns] = useState({
6 | column1: ["Item 1", "Item 2"],
7 | column2: ["Item 3", "Item 4"],
8 | column3: ["Item 5", "Item 6"],
9 | });
10 |
11 | const handleDragStart = (e, item, fromColumn) => {
12 | e.dataTransfer.setData("item", item);
13 | e.dataTransfer.setData("fromColumn", fromColumn);
14 | };
15 |
16 | const handleDrop = (e, toColumn) => {
17 | const item = e.dataTransfer.getData("item");
18 | const fromColumn = e.dataTransfer.getData("fromColumn");
19 |
20 | if (fromColumn === toColumn) return;
21 |
22 | setColumns((prevState) => {
23 | const newFromColumn = prevState[fromColumn].filter((i) => i !== item);
24 | const newToColumn = [...prevState[toColumn], item];
25 | return {
26 | ...prevState,
27 | [fromColumn]: newFromColumn,
28 | [toColumn]: newToColumn,
29 | };
30 | });
31 | };
32 |
33 | const handleDragOver = (e) => {
34 | e.preventDefault();
35 | };
36 |
37 | return (
38 |
39 |
40 | {Object.keys(columns).map((column) => (
41 |
handleDrop(e, column)}
44 | onDragOver={handleDragOver}
45 | key={column}
46 | >
47 | {columns[column].map((item, index) => (
48 |
handleDragStart(e, item, column)}
53 | >
54 | {item}
55 |
56 | ))}
57 |
58 | ))}
59 |
60 |
61 | );
62 | };
63 |
64 | export default App;
65 |
--------------------------------------------------------------------------------
/day2-drag-and-drop/src/Column.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export const Column = ({ column, onDrop, onDragOver, columns, onDragStart, onDragEnd, onCreateNewItem }) => {
4 | return (
5 | onDrop(event, column)}
9 | onDragOver={onDragOver}>
10 |
11 |
12 | {column}
13 | ({columns[column].length})
14 |
15 |
16 | {columns[column].map((item, index) => (
17 | onDragStart(event, item, column, index)}
20 | className="item"
21 | onDragOver={onDragOver}
22 | onDrop={(event) => onDrop(event, column, index)}
23 | key={item}
24 | onDragEnd={onDragEnd}
25 | >
26 | {item}
27 |
28 | ))}
29 |
30 |
31 |
38 |
39 | )
40 | }
41 |
--------------------------------------------------------------------------------
/day2-drag-and-drop/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/day2-drag-and-drop/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | const root = ReactDOM.createRoot(document.getElementById('root'));
8 | root.render(
9 |
10 |
11 |
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/day2-drag-and-drop/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/day2-drag-and-drop/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/day2-drag-and-drop/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/day3-progressive-web-app/README.md:
--------------------------------------------------------------------------------
1 | YT VIDEO : https://youtu.be/b7mfxPBqO6Y?si=W4X4CSsP0ZoKTVvh
2 |
3 |
4 | ### Service Worker PWA with Offline Support
5 |
6 | #### Overview
7 |
8 | This repository implements a Progressive Web App (PWA) with offline support using a service worker. The PWA allows users to access certain parts of the application even when they are offline, enhancing user experience and providing reliability in varying network conditions.
9 |
10 | #### What is a Service Worker?
11 |
12 | A service worker is a script that the browser runs in the background, separate from the web page. It enables features that don't require a web page or user interaction, such as background sync, push notifications, and, most importantly, offline support through caching. Service workers are crucial for implementing a PWA because they can intercept network requests and serve cached content, ensuring the app remains functional even when the user loses internet connectivity.
13 |
14 |
15 |
16 | ### Manifest JSON
17 |
18 | The `manifest.json` file plays a crucial role in making your web application a Progressive Web App (PWA). It provides the necessary metadata for your app, allowing it to be installed on a user's device and displayed as a standalone application, similar to a native app.
19 |
20 | #### Key Elements in `manifest.json`
21 |
22 | 1. **`name` and `short_name`:**
23 | ```json
24 | {
25 | "name": "Drag And Drop",
26 | "short_name": "Drag And Drop"
27 | }
28 | ```
29 | - **Purpose:** The `name` is the full name of your PWA, while `short_name` is a shortened version used when there is limited space (e.g., app icons on the home screen).
30 | - **Benefit:** These names ensure that your app is easily identifiable on users' devices.
31 |
32 | 2. **`description`:**
33 | ```json
34 | {
35 | "description": "Table item drag and drop"
36 | }
37 | ```
38 | - **Purpose:** Provides a brief explanation of what your app does. This description might be displayed in app stores or installation prompts.
39 | - **Benefit:** Helps users understand the purpose of your app before installation.
40 |
41 | 3. **`icons`:**
42 | ```json
43 | {
44 | "icons": [
45 | {
46 | "src": "cropped.png",
47 | "sizes": "192x192",
48 | "type": "image/png"
49 | }
50 | ]
51 | }
52 | ```
53 | - **Purpose:** Specifies the icon that will be used for the app when installed on a user's device. The `sizes` attribute defines the dimensions of the icon, and `type` indicates the image format.
54 | - **Benefit:** A well-chosen icon enhances brand recognition and provides a professional appearance on the home screen or app launcher.
55 |
56 | 4. **`start_url`:**
57 | ```json
58 | {
59 | "start_url": "/index.html"
60 | }
61 | ```
62 | - **Purpose:** Defines the URL that should be loaded when the app is launched from the home screen. It usually points to the main entry point of your application.
63 | - **Benefit:** Ensures users start at the correct page every time they open the app, providing a consistent experience.
64 |
65 | 5. **`display`:**
66 | ```json
67 | {
68 | "display": "standalone"
69 | }
70 | ```
71 | - **Purpose:** Controls how the app is displayed to the user. `standalone` removes the browser UI (like the address bar), making the app feel more like a native application.
72 | - **Benefit:** Offers a more immersive experience by hiding browser-specific elements.
73 |
74 | 6. **`background_color` and `theme_color`:**
75 | ```json
76 | {
77 | "background_color": "#fff",
78 | "theme_color": "#4CAF50"
79 | }
80 | ```
81 | - **Purpose:** `background_color` is the color used while the app is loading, and `theme_color` is the color of the browser UI. These enhance the visual appeal of your app.
82 | - **Benefit:** Ensures the app's appearance is consistent with your brand's color scheme, providing a polished user experience.
83 |
84 |
85 | #### Code Explanation
86 |
87 | The provided service worker script handles three main events: `install`, `fetch`, and `activate`.
88 |
89 | 1. **Install Event:**
90 | ```javascript
91 | self.addEventListener('install', (event) => {
92 | event.waitUntil(
93 | caches.open(CACHE_NAME)
94 | .then((cache) => {
95 | return cache.addAll(CAHCE_URLS);
96 | })
97 | );
98 | });
99 | ```
100 | - **Purpose:** During the installation of the service worker, specific URLs (defined in `CAHCE_URLS`) are cached. This ensures that these resources are available offline.
101 | - **Benefit:** By pre-caching essential assets, the app can load faster on subsequent visits and remain available offline.
102 |
103 | 2. **Fetch Event:**
104 | ```javascript
105 | self.addEventListener('fetch', (event) => {
106 |
107 | if (event.request.mode === 'navigate') {
108 | event.respondWith(
109 | fetch(event.request)
110 | .catch(() => caches.match(OFFLINE_URL))
111 | );
112 |
113 | } else {
114 | event.respondWith(
115 | caches.match(event.request)
116 | .then((response) => {
117 | if (response) {
118 | return response;
119 | }
120 | return fetch(event.request);
121 | })
122 | );
123 | }
124 |
125 | });
126 | ```
127 | - **Purpose:** This event handles all network requests. If the request is for navigation (e.g., the user navigates to a new page), it tries to fetch the resource from the network. If the network is unavailable, it serves the offline page instead.
128 | - **Benefit:** Users can continue to navigate the app and view a custom offline page when they lose connectivity, providing a seamless user experience.
129 |
130 | 3. **Activate Event:**
131 | ```javascript
132 | self.addEventListener('activate', (event) => {
133 | event.waitUntil(caches.keys().then((cacheNames) => {
134 | return Promise.all(
135 | cacheNames.filter((cacheName) => cacheName !== CACHE_NAME)
136 | .map((cacheName) => caches.delete(cacheName))
137 | );
138 | }))
139 | });
140 | ```
141 | - **Purpose:** This event is triggered when the service worker is activated. It ensures that old caches are deleted, keeping the cache storage clean and up-to-date.
142 | - **Benefit:** Prevents issues with stale data by ensuring that only the latest resources are cached, improving performance and reliability.
143 |
144 | #### Use Case
145 |
146 | The PWA implementation is particularly useful for scenarios where users may experience intermittent connectivity or want to access the app in offline mode, such as:
147 | - **Task Management Applications:** Users can manage tasks even when offline, with changes synced once connectivity is restored.
148 | - **Content-Heavy Applications:** Apps with lots of static content (e.g., articles, tutorials) can preload content, so it’s accessible offline.
149 |
150 | #### Benefits
151 |
152 | - **Improved User Experience:** The ability to load the application quickly and maintain functionality offline leads to a smoother user experience.
153 | - **Increased Reliability:** Users can trust that the app will work even with poor or no internet connection.
154 | - **Enhanced Performance:** Pre-cached assets reduce load times and network requests, making the app feel faster and more responsive.
155 |
156 | This implementation ensures that your application remains accessible, reliable, and performant, even in challenging network conditions.
157 |
--------------------------------------------------------------------------------
/day3-progressive-web-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "day2-drag-and-drop",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.17.0",
7 | "@testing-library/react": "^13.4.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "react": "^18.3.1",
10 | "react-dom": "^18.3.1",
11 | "react-scripts": "5.0.1",
12 | "web-vitals": "^2.1.4"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test",
18 | "eject": "react-scripts eject"
19 | },
20 | "eslintConfig": {
21 | "extends": [
22 | "react-app",
23 | "react-app/jest"
24 | ]
25 | },
26 | "browserslist": {
27 | "production": [
28 | ">0.2%",
29 | "not dead",
30 | "not op_mini all"
31 | ],
32 | "development": [
33 | "last 1 chrome version",
34 | "last 1 firefox version",
35 | "last 1 safari version"
36 | ]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/day3-progressive-web-app/public/cropped.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day3-progressive-web-app/public/cropped.png
--------------------------------------------------------------------------------
/day3-progressive-web-app/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
19 |
28 | Drag And Drop Application
29 |
30 |
31 | You need to enable JavaScript to run this app.
32 |
33 |
49 |
50 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/day3-progressive-web-app/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Drag And Drop",
3 | "short_name": "Drag And Drop",
4 | "description": "Table item drag and drop",
5 | "icons": [
6 | {
7 | "src": "cropped.png",
8 | "sizes": "192x192",
9 | "type": "image/png"
10 | }
11 | ],
12 | "start_url": "/index.html",
13 | "display": "standalone",
14 | "background_color": "#fff",
15 | "theme_color": "#4CAF50"
16 | }
--------------------------------------------------------------------------------
/day3-progressive-web-app/public/offline.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Drag And Drop Application - Offline
11 |
12 |
13 | Offline Page
14 | You are currently offline. Please check your internet connection.
15 | You need to enable JavaScript to run this app.
16 |
17 |
18 |
19 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/day3-progressive-web-app/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/day3-progressive-web-app/public/serviceWorker.js:
--------------------------------------------------------------------------------
1 | const CACHE_NAME = 'drag-drop-cache';
2 | const OFFLINE_URL = '/offline.html'
3 | const CAHCE_URLS = [
4 | '/',
5 | '/index.html',
6 | OFFLINE_URL
7 | ]
8 |
9 |
10 | // eslint-disable-next-line no-restricted-globals
11 | self.addEventListener('install', (event) => {
12 | event.waitUntil(
13 | caches.open(CACHE_NAME)
14 | .then((cache) => {
15 | return cache.addAll(CAHCE_URLS);
16 | })
17 | );
18 | });
19 |
20 | // eslint-disable-next-line no-restricted-globals
21 | self.addEventListener('fetch', (event) => {
22 |
23 | if (event.request.mode === 'navigate') {
24 | // Handle navigation requests
25 | event.respondWith(
26 | fetch(event.request)
27 | .catch(() => caches.match(OFFLINE_URL))
28 | );
29 |
30 | } else {
31 | event.respondWith(
32 | caches.match(event.request)
33 | .then((response) => {
34 | if (response) {
35 | return response;
36 | }
37 | return fetch(event.request);
38 | })
39 | );
40 | }
41 |
42 | });
43 |
44 | // Activate event - clean up old caches
45 | // eslint-disable-next-line no-restricted-globals
46 | self.addEventListener('activate', (event) => {
47 | event.waitUntil(caches.keys().then((cacheNames) => {
48 | return Promise.all(
49 | cacheNames.filter((cacheName) => cacheName !== CACHE_NAME)
50 | .map((cacheName) => caches.delete(cacheName))
51 | );
52 | }))
53 | })
--------------------------------------------------------------------------------
/day3-progressive-web-app/src/App.css:
--------------------------------------------------------------------------------
1 | .board {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | padding: 20px;
6 | min-height: 100vh;
7 | background-color: #f0f0f0; /* added a light gray background */
8 | }
9 |
10 | .columns {
11 | display: flex;
12 | flex-wrap: wrap;
13 | justify-content: center;
14 | margin-top: 50px;
15 | }
16 |
17 |
18 | .column {
19 | background-color: #f7f7f7;
20 | border: 1px solid #ddd;
21 | border-radius: 5px;
22 | padding: 10px;
23 | margin: 10px;
24 | width: 250px;
25 | display: flex;
26 | flex-direction: column;
27 | justify-content: space-between;
28 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* added a subtle box shadow */
29 | }
30 |
31 | .column h2 {
32 | margin-top: 0;
33 | font-weight: bold; /* made the column title bold */
34 | }
35 |
36 | .column h2 .heading {
37 | color: lightcoral;
38 | }
39 |
40 | .column h2 .count {
41 | color: darkgray;
42 | margin-left: 10px;
43 | }
44 |
45 |
46 | .list-parent {
47 | padding: 0;
48 | }
49 |
50 | .item {
51 | list-style-type: none;
52 | background-color: #fff;
53 | padding: 10px;
54 | border: 1px solid #ddd;
55 | border-radius: 5px;
56 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
57 | margin-block: 5px;
58 | cursor: move; /* a/* added a move cursor to indicate draggability */
59 | }
60 |
61 | .item:last-child {
62 | border-bottom: none;
63 | }
64 |
65 | .new-item-input-form {
66 | margin-top: 5rem;
67 | }
68 |
69 | .new-item-input {
70 | padding: 10px;
71 | border: 1px solid #ccc;
72 | border-radius: 5px;
73 | width: 100%;
74 | box-sizing: border-box; /* added box-sizing to prevent overflow */
75 | }
76 |
77 | .add-item-btn:hover {
78 | background-color: #3e8e41;
79 | }
80 |
81 |
82 | .add-column-btn {
83 | background-color: #4CAF50;
84 | color: #fff;
85 | border: none;
86 | padding: 10px 20px;
87 | font-size: 16px;
88 | cursor: pointer;
89 | transition: background-color 0.2s; /* added a transition for the button hover effect */
90 | position: absolute;
91 | right: 20px;
92 | }
93 |
94 | .add-column-btn:hover {
95 | background-color: #3e8e41;
96 | }
97 |
98 | /* added animation for dragging and dropping */
99 | .dragging {
100 | opacity: 0.3;
101 | transform: scale(0);
102 | transition: transform 0.2s, opacity 0.2s;
103 | }
104 |
105 | .dropping {
106 | transform: scale(1.1);
107 | transition: transform 0.2s;
108 | }
--------------------------------------------------------------------------------
/day3-progressive-web-app/src/App.js:
--------------------------------------------------------------------------------
1 | import { Fragment, useState } from 'react';
2 | import { Column } from './Column';
3 | import './App.css';
4 |
5 | function App() {
6 | const [columns, setColumns] = useState({
7 | column1: ['item1', 'item2'],
8 | column2: ['item3', 'item4']
9 | });
10 |
11 | const swapItems = (fromColumn, fromIndex, toColumn, toIndex) => {
12 | const fromData = columns[fromColumn];
13 | const toData = columns[toColumn];
14 |
15 | if (fromColumn === toColumn) {
16 | [fromData[toIndex], fromData[fromIndex]] = [fromData[fromIndex], fromData[toIndex]];
17 | } else {
18 | const [item] = fromData.splice(fromIndex, 1);
19 | toData.splice(toIndex, 0, item);
20 | }
21 |
22 | setColumns((prev) => ({
23 | ...prev,
24 | [fromColumn]: fromData,
25 | [toColumn]: toData
26 | }));
27 | };
28 |
29 |
30 | const onDrop = (event, toColumn, toIndex) => {
31 | event.stopPropagation();
32 | const item = event.dataTransfer.getData('item');
33 | const fromColumn = event.dataTransfer.getData('fromColumn');
34 | const fromIndex = parseInt(event.dataTransfer.getData('fromIndex'), 10);
35 |
36 | //animation
37 | event.target.classList.add('dropping');
38 | setTimeout(() => {
39 | event.target.classList.remove('dropping');
40 | }, 200);
41 |
42 | if (typeof toIndex !== 'number') {
43 | // Drop on column, append to end and remove from original column
44 | setColumns((prev) => {
45 | const newColumns = { ...prev };
46 | newColumns[toColumn] = [...newColumns[toColumn], item];
47 | newColumns[fromColumn] = newColumns[fromColumn].filter((_, i) => i !== fromIndex);
48 | return newColumns;
49 | });
50 | } else {
51 | // swap if same column or swapping from another column
52 | swapItems(fromColumn, fromIndex, toColumn, toIndex);
53 | }
54 |
55 | };
56 |
57 | const onDragOver = (event) => {
58 | event.preventDefault();
59 | };
60 |
61 | const onDragEnd = (event) => {
62 | event.target.classList.remove('dragging');
63 | }
64 |
65 | const onDragStart = (event, item, fromColumn, fromIndex) => {
66 | event.dataTransfer.setData('item', item);
67 | event.dataTransfer.setData('fromColumn', fromColumn);
68 | event.dataTransfer.setData('fromIndex', fromIndex);
69 | event.target.classList.add('dragging');
70 | };
71 |
72 | const onCreateNewItem = (event, column) => {
73 | event.preventDefault();
74 | const data = Object.fromEntries(new FormData(event.target));
75 | setColumns((prev) => ({
76 | ...prev,
77 | [column]: [...prev[column], data[column]]
78 | }));
79 | event.target.reset();
80 | };
81 |
82 | const createColumn = () => {
83 | const totalColumns = Object.keys(columns).length;
84 | const newColumnName = `column${totalColumns + 1}`;
85 | setColumns((prev) => ({
86 | ...prev,
87 | [newColumnName]: []
88 | }));
89 | };
90 |
91 | return (
92 |
93 |
94 |
95 | {Object.keys(columns).map((column) => (
96 |
105 | ))}
106 |
107 |
108 | + Add Column
109 |
110 |
111 |
112 | );
113 | }
114 |
115 | export default App;
--------------------------------------------------------------------------------
/day3-progressive-web-app/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import "./App.css";
3 |
4 | const App = () => {
5 | const [columns, setColumns] = useState({
6 | column1: ["Item 1", "Item 2"],
7 | column2: ["Item 3", "Item 4"],
8 | column3: ["Item 5", "Item 6"],
9 | });
10 |
11 | const handleDragStart = (e, item, fromColumn) => {
12 | e.dataTransfer.setData("item", item);
13 | e.dataTransfer.setData("fromColumn", fromColumn);
14 | };
15 |
16 | const handleDrop = (e, toColumn) => {
17 | const item = e.dataTransfer.getData("item");
18 | const fromColumn = e.dataTransfer.getData("fromColumn");
19 |
20 | if (fromColumn === toColumn) return;
21 |
22 | setColumns((prevState) => {
23 | const newFromColumn = prevState[fromColumn].filter((i) => i !== item);
24 | const newToColumn = [...prevState[toColumn], item];
25 | return {
26 | ...prevState,
27 | [fromColumn]: newFromColumn,
28 | [toColumn]: newToColumn,
29 | };
30 | });
31 | };
32 |
33 | const handleDragOver = (e) => {
34 | e.preventDefault();
35 | };
36 |
37 | return (
38 |
39 |
40 | {Object.keys(columns).map((column) => (
41 |
handleDrop(e, column)}
44 | onDragOver={handleDragOver}
45 | key={column}
46 | >
47 | {columns[column].map((item, index) => (
48 |
handleDragStart(e, item, column)}
53 | >
54 | {item}
55 |
56 | ))}
57 |
58 | ))}
59 |
60 |
61 | );
62 | };
63 |
64 | export default App;
65 |
--------------------------------------------------------------------------------
/day3-progressive-web-app/src/Column.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export const Column = ({ column, onDrop, onDragOver, columns, onDragStart, onDragEnd, onCreateNewItem }) => {
4 | return (
5 | onDrop(event, column)}
9 | onDragOver={onDragOver}>
10 |
11 |
12 | {column}
13 | ({columns[column].length})
14 |
15 |
16 | {columns[column].map((item, index) => (
17 | onDragStart(event, item, column, index)}
20 | className="item"
21 | onDragOver={onDragOver}
22 | onDrop={(event) => onDrop(event, column, index)}
23 | key={item}
24 | onDragEnd={onDragEnd}
25 | >
26 | {item}
27 |
28 | ))}
29 |
30 |
31 |
38 |
39 | )
40 | }
41 |
--------------------------------------------------------------------------------
/day3-progressive-web-app/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/day3-progressive-web-app/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | const root = ReactDOM.createRoot(document.getElementById('root'));
8 | root.render(
9 |
10 |
11 |
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/day3-progressive-web-app/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/day3-progressive-web-app/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/day3-progressive-web-app/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/day4-browser-encryption/README.md:
--------------------------------------------------------------------------------
1 | YT Video : https://youtu.be/EuTqlGTbmqs?si=llpAAhoD0stT2d9l
2 |
3 |
4 |
5 | # Encryption of Storage Data
6 |
7 | This project demonstrates how to securely store and retrieve data in the browser's `localStorage` using simple XOR encryption. The implementation includes functions for encryption, decryption, and integration with `localStorage`.
8 |
9 |
10 | ## Overview
11 |
12 | The provided code encrypts data before storing it in `localStorage` and decrypts it when retrieving it. This adds a layer of security by ensuring that sensitive information is not stored in plaintext. XOR encryption is a basic encryption method, where each character of the input is XORed with a character from a secret key.
13 |
14 | ## Installation
15 |
16 | To use this code in your project, simply copy the `encryption.js` and `localstorage.js` files into your project directory.
17 |
18 | Ensure your project is set up to handle ES6 modules, as the code uses the `import` and `export` syntax.
19 |
20 | ## Usage
21 |
22 | ### 1. Encryption and Decryption
23 |
24 | The core of this implementation is the XOR-based encryption and decryption functions:
25 |
26 | ```javascript
27 | export const xorEncryptDecrypt = (input, secretKey) => {
28 | let output = '';
29 | for (let i = 0; i < input.length; i++) {
30 | const inputCode = input.charCodeAt(i);
31 | const secretCode = secretKey.charCodeAt(i % secretKey.length);
32 | const xor = inputCode ^ secretCode;
33 | output += String.fromCharCode(xor);
34 | }
35 | return output;
36 | }
37 |
38 | export const encrypt = (data, secretKey) => {
39 | const stringifiedData = JSON.stringify(data);
40 | return xorEncryptDecrypt(stringifiedData, secretKey);
41 | }
42 |
43 | export const decrypt = (data, secretKey) => {
44 | try {
45 | const decryptedData = xorEncryptDecrypt(data, secretKey);
46 | return JSON.parse(decryptedData);
47 | } catch {
48 | return null;
49 | }
50 | }
51 | ```
52 |
53 | ### 2. LocalStorage Integration
54 |
55 | The functions to set and get encrypted data from `localStorage` are as follows:
56 |
57 | ```javascript
58 | import { decrypt, encrypt } from "./encryption"
59 |
60 | const SECRET_CODE = 'code123';
61 |
62 | export const setData = (key, data) => {
63 | const encrypted = encrypt(data, SECRET_CODE);
64 | localStorage.setItem(key, encrypted);
65 | }
66 |
67 | export const getData = (key) => {
68 | const data = localStorage.getItem(key);
69 | if (!data) return null;
70 | return decrypt(data, SECRET_CODE);
71 | }
72 | ```
73 |
74 | ### 3. Application Integration
75 |
76 | In your React application, you can use the encryption and decryption methods within your components as shown:
77 |
78 | ```javascript
79 | const handleChange = (e) => {
80 | const { id, value } = e.target;
81 | setData(id, value);
82 | setFormData((prevData) => ({
83 | ...prevData,
84 | [id]: value,
85 | }));
86 | };
87 |
88 | useEffect(() => {
89 | const username = getData('username');
90 | const email = getData('email');
91 | const phone = getData('phone');
92 | setFormData({
93 | username,
94 | email,
95 | phone,
96 | });
97 | }, []);
98 | ```
99 |
100 | ## Example
101 |
102 | When a user inputs data in a form, it is encrypted using the `SECRET_CODE` and stored in `localStorage`. Upon reloading the page, the data is retrieved, decrypted, and used to populate the form fields.
103 |
104 | ```javascript
105 | setData('username', 'JohnDoe');
106 | const username = getData('username');
107 | console.log(username); // Outputs 'JohnDoe'
108 | ```
109 |
110 | This ensures that sensitive information like usernames, emails, and phone numbers are not stored in plain text in the browser's `localStorage`.
111 |
--------------------------------------------------------------------------------
/day4-browser-encryption/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "day4-browser-encryption",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.17.0",
7 | "@testing-library/react": "^13.4.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "crypto": "^1.0.1",
10 | "crypto-browserify": "^3.12.0",
11 | "react": "^18.3.1",
12 | "react-dom": "^18.3.1",
13 | "react-scripts": "5.0.1",
14 | "web-vitals": "^2.1.4"
15 | },
16 | "scripts": {
17 | "start": "react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test",
20 | "eject": "react-scripts eject"
21 | },
22 | "eslintConfig": {
23 | "extends": [
24 | "react-app",
25 | "react-app/jest"
26 | ]
27 | },
28 | "browserslist": {
29 | "production": [
30 | ">0.2%",
31 | "not dead",
32 | "not op_mini all"
33 | ],
34 | "development": [
35 | "last 1 chrome version",
36 | "last 1 firefox version",
37 | "last 1 safari version"
38 | ]
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/day4-browser-encryption/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day4-browser-encryption/public/favicon.ico
--------------------------------------------------------------------------------
/day4-browser-encryption/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 | You need to enable JavaScript to run this app.
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/day4-browser-encryption/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day4-browser-encryption/public/logo192.png
--------------------------------------------------------------------------------
/day4-browser-encryption/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day4-browser-encryption/public/logo512.png
--------------------------------------------------------------------------------
/day4-browser-encryption/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/day4-browser-encryption/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/day4-browser-encryption/src/App.css:
--------------------------------------------------------------------------------
1 | .form-container {
2 | width: 300px;
3 | margin: 0 auto;
4 | padding: 20px;
5 | background-color: #f4f4f4;
6 | border-radius: 8px;
7 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
8 | }
9 |
10 | .form-group {
11 | margin-bottom: 15px;
12 | }
13 |
14 | label {
15 | display: block;
16 | margin-bottom: 5px;
17 | font-weight: bold;
18 | }
19 |
20 | input[type="text"],
21 | input[type="email"],
22 | input[type="tel"] {
23 | width: 100%;
24 | padding: 8px;
25 | border: 1px solid #ccc;
26 | border-radius: 4px;
27 | box-sizing: border-box;
28 | }
29 |
30 | .display-data {
31 | margin-top: 20px;
32 | padding: 10px;
33 | background-color: #e7f3ff;
34 | border-radius: 8px;
35 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
36 | }
37 |
38 | .display-data p {
39 | margin: 5px 0;
40 | font-size: 14px;
41 | color: #333;
42 | }
43 |
--------------------------------------------------------------------------------
/day4-browser-encryption/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import './App.css'; // Import the CSS file
3 | import { getData, setData } from './utils/localstorage';
4 |
5 | function App() {
6 | const [formData, setFormData] = useState({
7 | username: '',
8 | email: '',
9 | phone: ''
10 | })
11 |
12 | const handleChange = (e) => {
13 | const { id, value } = e.target;
14 | setData(id, value)
15 | setFormData((prevData) => ({
16 | ...prevData,
17 | [id]: value,
18 | }));
19 | };
20 |
21 | useEffect(() => {
22 | const username = getData('username');
23 | const email = getData('email');
24 | const phone = getData('phone');
25 | setFormData({
26 | username,
27 | email,
28 | phone,
29 | })
30 | }, [])
31 |
32 | return (
33 |
34 |
66 |
67 | {formData.username &&
Username: {formData.username}
}
68 | {formData.email &&
Email: {formData.email}
}
69 | {formData.phone &&
Phone Number: {formData.phone}
}
70 |
71 |
72 | );
73 | }
74 |
75 | export default App;
76 |
--------------------------------------------------------------------------------
/day4-browser-encryption/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render( );
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/day4-browser-encryption/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Arial, sans-serif;
3 | background-color: #f0f0f0;
4 | }
5 |
6 | .container {
7 | width: 50%;
8 | margin: 40px auto;
9 | padding: 20px;
10 | border: 1px solid #ccc;
11 | border-radius: 10px;
12 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
13 | }
14 |
15 | .title {
16 | text-align: center;
17 | margin-bottom: 20px;
18 | }
19 |
20 | .button-group {
21 | display: flex;
22 | justify-content: space-between;
23 | margin-bottom: 20px;
24 | }
25 |
26 | .btn {
27 | background-color: #4CAF50;
28 | color: #fff;
29 | padding: 10px 20px;
30 | border: none;
31 | border-radius: 5px;
32 | cursor: pointer;
33 | }
34 |
35 | .btn:hover {
36 | background-color: #3e8e41;
37 | }
38 |
39 | .data-container {
40 | display: flex;
41 | flex-direction: column;
42 | align-items: center;
43 | }
44 |
45 | .data-section {
46 | margin-bottom: 20px;
47 | }
48 |
49 | .section-title {
50 | margin-bottom: 10px;
51 | }
52 |
53 | .data-text {
54 | font-size: 18px;
55 | font-weight: bold;
56 | margin-bottom: 10px;
57 | }
58 |
59 | .data-list {
60 | list-style: none;
61 | padding: 0;
62 | margin: 0;
63 | }
64 |
65 | .data-item {
66 | padding: 10px;
67 | border-bottom: 1px solid #ccc;
68 | }
69 |
70 | .data-item:last-child {
71 | border-bottom: none;
72 | }
--------------------------------------------------------------------------------
/day4-browser-encryption/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | const root = ReactDOM.createRoot(document.getElementById('root'));
8 | root.render(
9 |
10 |
11 |
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/day4-browser-encryption/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/day4-browser-encryption/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/day4-browser-encryption/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/day4-browser-encryption/src/utils/encryption.js:
--------------------------------------------------------------------------------
1 | export const xorEncryptDecrypt = (input, secretKey) => {
2 | let output = '';
3 | for (let i = 0; i < input.length; i++) {
4 | const inputCode = input.charCodeAt(i);
5 | const secretCode = secretKey.charCodeAt(i % secretKey.length)
6 | const xor = inputCode ^ secretCode; // any number
7 | output += String.fromCharCode(xor); // &~
8 | }
9 | return output
10 | }
11 |
12 | export const encrypt = (data, secretKey) => {
13 | const stringifiedData = JSON.stringify(data);
14 | return xorEncryptDecrypt(stringifiedData, secretKey)
15 | }
16 |
17 |
18 | export const decrypt = (data, secretKey) => {
19 | try {
20 | const decryptedData = xorEncryptDecrypt(data, secretKey);
21 | return JSON.parse(decryptedData)
22 | } catch {
23 | return null
24 | }
25 | }
--------------------------------------------------------------------------------
/day4-browser-encryption/src/utils/localstorage.js:
--------------------------------------------------------------------------------
1 | import { decrypt, encrypt } from "./encryption"
2 |
3 | const SECRET_CODE = 'code123'
4 |
5 |
6 | export const setData = (key, data) => {
7 | const encrypted = encrypt(data, SECRET_CODE)
8 | localStorage.setItem(key, encrypted)
9 | }
10 |
11 | export const getData = (key) => {
12 | const data = localStorage.getItem(key);
13 | if (!data) return null;
14 | return decrypt(data, SECRET_CODE)
15 | }
--------------------------------------------------------------------------------
/day5-microfrontend/README.md:
--------------------------------------------------------------------------------
1 | ## How to use?
2 | 1. clone this repo.
3 | 2. run `npm install` by going each of folder - ( form, host1, host2)
4 | 3. start app by `npm start` of each host.
5 |
6 | ## PORT of each app
7 | 1. form - localhost:3000 - Must run this port on 3000 or you can do change from .env in host1, host2
8 | 2. host1 - localhost:3001
9 | 3. host2 - localhost:3002
10 |
11 |
12 | ## Microfrontend Architecture: Reusing a Form Component Across Multiple Hosts
13 |
14 | This documentation covers how to use a `Form` as a microfrontend with `host1` and `host2` acting as a connector to render and manage the form component across multiple applications.
15 |
16 | ## Overview
17 |
18 | The goal of this architecture is to allow reusability of the `Form` component in different host applications using microfrontend principles. Each host can dynamically load and render the form from a separate source (microfrontend) while passing in custom logic like handlers and states.
19 |
20 | ## Project Structure
21 |
22 | Here’s the grammatically corrected version:
23 |
24 | ### 1. Webpack Override
25 |
26 | First, install `react-app-rewired`:
27 |
28 | ```
29 | npm install react-app-rewired
30 | ```
31 |
32 | Next, create a file in the root directory called `config-overrides.js`:
33 |
34 | ```js
35 | module.exports = {
36 | webpack: (config, env) => {
37 | config.optimization.runtimeChunk = false;
38 | config.optimization.splitChunks = {
39 | cacheGroups: {
40 | default: false,
41 | },
42 | };
43 |
44 | config.output.filename = "static/js/[name].js";
45 |
46 | config.plugins[5].options.filename = "static/css/[name].css";
47 | config.plugins[5].options.moduleFilename = () => "static/css/main.css";
48 | return config;
49 | },
50 | };
51 | ```
52 |
53 | In `package.json`, replace the default `react-scripts` commands with the following commands for `start`, `build`, and `test`:
54 |
55 | ```json
56 | "scripts": {
57 | "start": "PORT=3000 react-app-rewired start",
58 | "build": "react-app-rewired build",
59 | "test": "react-app-rewired test",
60 | "eject": "react-app-rewired eject"
61 | }
62 | ```
63 |
64 | This setup overrides the default Webpack configuration, allowing for custom optimization and file naming strategies.
65 |
66 | ### 2. **Form Microfrontend**
67 | - A simple React component that can be embedded in any host via microfrontend architecture.
68 | - The form collects user input (name, email, city, country) and uses a handler to submit data.
69 | - The `handler` contains customizable logic for how the form behaves, allowing hosts to define how form submission and other interactions are handled.
70 |
71 | ```jsx
72 | import React from "react";
73 | import "./App.css";
74 |
75 | export const Form = ({ handler }) => {
76 |
77 | const handleSubmit = (e) => {
78 | e.preventDefault();
79 | if (!handler?.submit) return;
80 | const formData = new FormData(e.target);
81 | const data = Object.fromEntries(formData);
82 | return handler.submit(data);
83 | };
84 |
85 | return (
86 |
87 |
88 |
89 |
90 |
Hello {handler?.name}
91 |
136 |
137 |
138 |
139 |
140 | );
141 | };
142 | ```
143 |
144 |
145 | # Understanding the `index.js` in Microfrontend
146 |
147 | The `index.js` file plays a crucial role in managing the lifecycle of the microfrontend. It defines how the microfrontend is rendered and unmounted when integrated into host applications. Let’s walk through the code step by step to understand its functionality.
148 |
149 | ## Step 1: **Import React and Other Dependencies**
150 |
151 | ```js
152 | import React from "react";
153 | import ReactDOM from "react-dom/client";
154 | import "./index.css";
155 | import App from "./App";
156 |
157 | window.renderForm = (containerId, history, handler) => {
158 | const root = ReactDOM.createRoot(document.getElementById(containerId));
159 | root.render( );
160 | };
161 |
162 | window.unmountForm = (containerId) => {
163 | const root = ReactDOM.createRoot(document.getElementById(containerId));
164 | root.unmount();
165 | };
166 |
167 | if (!document.getElementById("Form-container")) {
168 | const root = ReactDOM.createRoot(document.getElementById("root"));
169 | root.render( );
170 | }
171 |
172 | ```
173 |
174 |
175 |
176 | This `window.renderForm` requires three parameters to function correctly:
177 |
178 | - **containerId**: The ID of the DOM element where the microfrontend will be rendered.
179 | - **history**: A history object, which allows navigation within the microfrontend.
180 | - **handler**: A custom handler object passed from the host to manage events like form submission.
181 |
182 | ## Connector in Host
183 |
184 |
185 | ```jsx
186 | import React, { useEffect } from "react";
187 |
188 | export const MicroFrontend = ({ host, history, handler }) => {
189 | useEffect(() => {
190 | const scriptId = `micro-frontend-script-Form`;
191 |
192 | const renderMicroFrontend = () => {
193 | window[`renderForm`](`Form-container`, history, handler);
194 | };
195 |
196 | if (document.getElementById(scriptId)) {
197 | renderMicroFrontend();
198 | return;
199 | }
200 |
201 | //host: localhost:3000 // form
202 | fetch(`${host}/asset-manifest.json`)
203 | .then((res) => res.json())
204 | .then((manifest) => {
205 | const script = document.createElement("script");
206 | script.id = scriptId;
207 | script.crossOrigin = "";
208 | script.src = `${host}${manifest.files["main.js"]}`;
209 | script.onload = () => {
210 | renderMicroFrontend();
211 | };
212 | document.head.appendChild(script);
213 | });
214 |
215 | return () => {
216 | window[`unmountForm`] && window[`unmountForm`](`Form-container`);
217 | };
218 | });
219 |
220 | return ;
221 | };
222 |
223 | MicroFrontend.defaultProps = {
224 | document,
225 | window,
226 | };
227 |
228 |
229 | ```
230 |
231 | ## use case
232 |
233 | ```jsx
234 | import React, { useState } from "react";
235 | import { MicroFrontend } from "./MicroFrontend";
236 |
237 | import "./App.css";
238 | const { REACT_APP_FORM_HOST: formHost } = process.env;
239 |
240 | export const App = ({ history }) => {
241 |
242 | const [data, setData] = useState({})
243 | const [counter, setCounter] = useState(0)
244 |
245 | const handleSubmit = (data) => {
246 | setData(data)
247 | };
248 |
249 |
250 | const handler = {
251 | name: "From host1",
252 | submit: handleSubmit,
253 | counter,
254 | };
255 |
256 | return (
257 |
258 |
Micro frontend
259 |
setCounter(prev => prev + 1)}>Increment
260 |
268 |
form response : {JSON.stringify(data)}
269 |
270 | );
271 | };
272 |
273 | export default App;
274 |
275 | ```
276 |
277 |
278 |
--------------------------------------------------------------------------------
/day5-microfrontend/form/README.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/day5-microfrontend/form/config-overrides.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | webpack: (config, env) => {
3 | config.optimization.runtimeChunk = false;
4 | config.optimization.splitChunks = {
5 | cacheGroups: {
6 | default: false,
7 | },
8 | };
9 |
10 | config.output.filename = "static/js/[name].js";
11 |
12 | config.plugins[5].options.filename = "static/css/[name].css";
13 | config.plugins[5].options.moduleFilename = () => "static/css/main.css";
14 | return config;
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/day5-microfrontend/form/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "form",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.11.4",
7 | "@testing-library/react": "^11.1.0",
8 | "@testing-library/user-event": "^12.1.10",
9 | "bootstrap": "^5.0.2",
10 | "history": "^5.0.0",
11 | "react": "^18.3.1",
12 | "react-app-rewired": "^2.1.8",
13 | "react-dom": "^18.3.1",
14 | "react-router-dom": "^5.2.0",
15 | "react-scripts": "4.0.3",
16 | "web-vitals": "^1.0.1"
17 | },
18 | "scripts": {
19 | "start": "PORT=3000 && react-app-rewired start",
20 | "build": "react-app-rewired build",
21 | "test": "react-app-rewired test",
22 | "eject": "react-app-rewired eject"
23 | },
24 | "eslintConfig": {
25 | "extends": [
26 | "react-app",
27 | "react-app/jest"
28 | ]
29 | },
30 | "browserslist": {
31 | "production": [
32 | ">0.2%",
33 | "not dead",
34 | "not op_mini all"
35 | ],
36 | "development": [
37 | "last 1 chrome version",
38 | "last 1 firefox version",
39 | "last 1 safari version"
40 | ]
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/day5-microfrontend/form/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day5-microfrontend/form/public/favicon.ico
--------------------------------------------------------------------------------
/day5-microfrontend/form/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
18 |
19 |
28 | Form
29 |
30 |
31 | You need to enable JavaScript to run this app.
32 |
33 |
34 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/day5-microfrontend/form/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day5-microfrontend/form/public/logo192.png
--------------------------------------------------------------------------------
/day5-microfrontend/form/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day5-microfrontend/form/public/logo512.png
--------------------------------------------------------------------------------
/day5-microfrontend/form/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/day5-microfrontend/form/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/day5-microfrontend/form/src/App.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day5-microfrontend/form/src/App.css
--------------------------------------------------------------------------------
/day5-microfrontend/form/src/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
3 | import { createBrowserHistory } from "history";
4 | import { Form } from "./Form";
5 | import "./App.css";
6 |
7 | const defaultHistory = createBrowserHistory();
8 |
9 | export const App = ({ history = defaultHistory, handler }) => {
10 | return (
11 |
12 |
13 | }
17 | />
18 |
19 |
20 | );
21 | };
22 |
23 | export default App;
24 |
--------------------------------------------------------------------------------
/day5-microfrontend/form/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render( );
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/day5-microfrontend/form/src/Form.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./App.css";
3 |
4 | export const Form = ({ handler }) => {
5 |
6 | const handleSubmit = (e) => {
7 | e.preventDefault();
8 | if (!handler?.submit) return;
9 | const formData = new FormData(e.target);
10 | const data = Object.fromEntries(formData)
11 | return handler.submit(data);
12 | };
13 |
14 | return (
15 |
16 |
17 |
18 |
19 |
Hello {handler?.name}
20 |
65 |
66 |
67 |
68 |
69 | );
70 | };
71 |
72 | Form.defaultProps = {
73 | handler: {
74 | name: "Template form",
75 | submit: (e) => e.preventDefault(),
76 | },
77 | };
--------------------------------------------------------------------------------
/day5-microfrontend/form/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/day5-microfrontend/form/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import "./index.css";
4 | import App from "./App";
5 |
6 | window.renderForm = (containerId, history, handler) => {
7 | const root = ReactDOM.createRoot(document.getElementById(containerId));
8 | root.render( );
9 | };
10 |
11 | window.unmountForm = (containerId) => {
12 | const root = ReactDOM.createRoot(document.getElementById(containerId));
13 | root.unmount();
14 | };
15 |
16 | if (!document.getElementById("Form-container")) {
17 | const root = ReactDOM.createRoot(document.getElementById("root"));
18 | root.render( );
19 | }
--------------------------------------------------------------------------------
/day5-microfrontend/form/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/day5-microfrontend/form/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/day5-microfrontend/form/src/setupProxy.js:
--------------------------------------------------------------------------------
1 | module.exports = (app) => {
2 | app.use((req, res, next) => {
3 | res.header("Access-Control-Allow-Origin", "*");
4 | next();
5 | });
6 | };
7 |
--------------------------------------------------------------------------------
/day5-microfrontend/form/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/day5-microfrontend/form/src/utils.js:
--------------------------------------------------------------------------------
1 | export const getQueryParams = (url, param) => {
2 | return new URLSearchParams(url).get(param)
3 | }
--------------------------------------------------------------------------------
/day5-microfrontend/host1/README.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/day5-microfrontend/host1/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "host1",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.11.4",
7 | "@testing-library/react": "^11.1.0",
8 | "@testing-library/user-event": "^12.1.10",
9 | "bootstrap": "^5.0.2",
10 | "history": "^5.0.0",
11 | "react": "^18.3.1",
12 | "react-dom": "^18.3.1",
13 | "react-router-dom": "^5.2.0",
14 | "react-scripts": "4.0.3",
15 | "web-vitals": "^1.0.1"
16 | },
17 | "scripts": {
18 | "start": "PORT=3001 && react-scripts start",
19 | "build": "react-scripts build",
20 | "test": "react-scripts test",
21 | "eject": "react-scripts eject"
22 | },
23 | "eslintConfig": {
24 | "extends": [
25 | "react-app",
26 | "react-app/jest"
27 | ]
28 | },
29 | "browserslist": {
30 | "production": [
31 | ">0.2%",
32 | "not dead",
33 | "not op_mini all"
34 | ],
35 | "development": [
36 | "last 1 chrome version",
37 | "last 1 firefox version",
38 | "last 1 safari version"
39 | ]
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/day5-microfrontend/host1/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day5-microfrontend/host1/public/favicon.ico
--------------------------------------------------------------------------------
/day5-microfrontend/host1/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
19 |
28 | Host 1
29 |
30 |
31 | You need to enable JavaScript to run this app.
32 |
33 |
34 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/day5-microfrontend/host1/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day5-microfrontend/host1/public/logo192.png
--------------------------------------------------------------------------------
/day5-microfrontend/host1/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day5-microfrontend/host1/public/logo512.png
--------------------------------------------------------------------------------
/day5-microfrontend/host1/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/day5-microfrontend/host1/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/day5-microfrontend/host1/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | @media (prefers-reduced-motion: no-preference) {
11 | .App-logo {
12 | animation: App-logo-spin infinite 20s linear;
13 | }
14 | }
15 |
16 | .App-header {
17 | background-color: #282c34;
18 | min-height: 100vh;
19 | display: flex;
20 | flex-direction: column;
21 | align-items: center;
22 | justify-content: center;
23 | font-size: calc(10px + 2vmin);
24 | color: white;
25 | }
26 |
27 | .App-link {
28 | color: #61dafb;
29 | }
30 |
31 | @keyframes App-logo-spin {
32 | from {
33 | transform: rotate(0deg);
34 | }
35 | to {
36 | transform: rotate(360deg);
37 | }
38 | }
39 |
40 | .container {
41 | margin-top: 1rem;
42 | }
43 |
--------------------------------------------------------------------------------
/day5-microfrontend/host1/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { MicroFrontend } from "./MicroFrontend";
3 |
4 | import "./App.css";
5 | const { REACT_APP_FORM_HOST: formHost } = process.env;
6 |
7 | export const App = ({ history }) => {
8 |
9 | const [data, setData] = useState({})
10 | const [counter, setCounter] = useState(0)
11 |
12 | const handleSubmit = (data) => {
13 | setData(data)
14 | };
15 |
16 |
17 | const handler = {
18 | name: "From host1",
19 | submit: handleSubmit,
20 | counter,
21 | };
22 |
23 | return (
24 |
25 |
Micro frontend
26 |
setCounter(prev => prev + 1)}>Increment
27 |
35 |
form response : {JSON.stringify(data)}
36 |
37 | );
38 | };
39 |
40 | export default App;
41 |
--------------------------------------------------------------------------------
/day5-microfrontend/host1/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render( );
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/day5-microfrontend/host1/src/MicroFrontend.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 |
3 | export const MicroFrontend = ({ host, history, handler }) => {
4 | useEffect(() => {
5 | const scriptId = `micro-frontend-script-Form`;
6 |
7 | const renderMicroFrontend = () => {
8 | window[`renderForm`](`Form-container`, history, handler);
9 | };
10 |
11 | if (document.getElementById(scriptId)) {
12 | renderMicroFrontend();
13 | return;
14 | }
15 |
16 | //host: localhost:3000 // form
17 | fetch(`${host}/asset-manifest.json`)
18 | .then((res) => res.json())
19 | .then((manifest) => {
20 | const script = document.createElement("script");
21 | script.id = scriptId;
22 | script.crossOrigin = "";
23 | script.src = `${host}${manifest.files["main.js"]}`;
24 | script.onload = () => {
25 | renderMicroFrontend();
26 | };
27 | document.head.appendChild(script);
28 | });
29 |
30 | return () => {
31 | window[`unmountForm`] && window[`unmountForm`](`Form-container`);
32 | };
33 | });
34 |
35 | return ;
36 | };
37 |
38 | MicroFrontend.defaultProps = {
39 | document,
40 | window,
41 | };
42 |
--------------------------------------------------------------------------------
/day5-microfrontend/host1/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
12 | monospace;
13 | }
14 |
15 | .container {
16 | margin-top: 10px;
17 | }
18 |
19 | .light-blue{
20 | background-color: aquamarine;
21 | }
22 |
23 | .light-green{
24 | background-color: lightgreen;
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/day5-microfrontend/host1/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | const root = ReactDOM.createRoot(document.getElementById('root'));
8 | root.render(
9 |
10 |
11 |
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
--------------------------------------------------------------------------------
/day5-microfrontend/host1/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/day5-microfrontend/host1/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/day5-microfrontend/host1/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/day5-microfrontend/host2/README.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/day5-microfrontend/host2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "host2",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.11.4",
7 | "@testing-library/react": "^11.1.0",
8 | "@testing-library/user-event": "^12.1.10",
9 | "bootstrap": "^5.0.2",
10 | "history": "^5.0.0",
11 | "react": "^18.3.1",
12 | "react-dom": "^18.3.1",
13 | "react-router-dom": "^5.2.0",
14 | "react-scripts": "4.0.3",
15 | "web-vitals": "^1.0.1"
16 | },
17 | "scripts": {
18 | "start": "PORT=3002 && react-scripts start",
19 | "build": "react-scripts build",
20 | "test": "react-scripts test",
21 | "eject": "react-scripts eject"
22 | },
23 | "eslintConfig": {
24 | "extends": [
25 | "react-app",
26 | "react-app/jest"
27 | ]
28 | },
29 | "browserslist": {
30 | "production": [
31 | ">0.2%",
32 | "not dead",
33 | "not op_mini all"
34 | ],
35 | "development": [
36 | "last 1 chrome version",
37 | "last 1 firefox version",
38 | "last 1 safari version"
39 | ]
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/day5-microfrontend/host2/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day5-microfrontend/host2/public/favicon.ico
--------------------------------------------------------------------------------
/day5-microfrontend/host2/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
19 |
28 | Host 2
29 |
30 |
31 | You need to enable JavaScript to run this app.
32 |
33 |
34 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/day5-microfrontend/host2/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day5-microfrontend/host2/public/logo192.png
--------------------------------------------------------------------------------
/day5-microfrontend/host2/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day5-microfrontend/host2/public/logo512.png
--------------------------------------------------------------------------------
/day5-microfrontend/host2/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/day5-microfrontend/host2/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/day5-microfrontend/host2/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | @media (prefers-reduced-motion: no-preference) {
11 | .App-logo {
12 | animation: App-logo-spin infinite 20s linear;
13 | }
14 | }
15 |
16 | .App-header {
17 | background-color: #282c34;
18 | min-height: 100vh;
19 | display: flex;
20 | flex-direction: column;
21 | align-items: center;
22 | justify-content: center;
23 | font-size: calc(10px + 2vmin);
24 | color: white;
25 | }
26 |
27 | .App-link {
28 | color: #61dafb;
29 | }
30 |
31 | @keyframes App-logo-spin {
32 | from {
33 | transform: rotate(0deg);
34 | }
35 | to {
36 | transform: rotate(360deg);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/day5-microfrontend/host2/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { MicroFrontend } from "./MicroFrontend";
3 |
4 | import "./App.css";
5 |
6 | const { REACT_APP_FORM_HOST: formHost } = process.env;
7 |
8 | export const App = ({ history }) => {
9 | const [data, setData] = useState()
10 |
11 | const handleSubmit = (data) => {
12 | setData(data)
13 | };
14 |
15 | const handler = {
16 | name: "From host 2",
17 | submit: handleSubmit,
18 | };
19 |
20 | return (
21 |
22 |
23 |
Micro frontend
24 |
32 |
33 |
form response : {JSON.stringify(data)}
34 |
35 | );
36 | };
37 |
38 | export default App;
39 |
--------------------------------------------------------------------------------
/day5-microfrontend/host2/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render( );
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/day5-microfrontend/host2/src/MicroFrontend.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 |
3 | export const MicroFrontend = ({ host, history, handler }) => {
4 | useEffect(() => {
5 | const scriptId = `micro-frontend-script-Form`;
6 |
7 | const renderMicroFrontend = () => {
8 | window[`renderForm`](`Form-container`, history, handler);
9 | };
10 |
11 | if (document.getElementById(scriptId)) {
12 | renderMicroFrontend();
13 | return;
14 | }
15 |
16 | //host: localhost:3000 // form
17 | fetch(`${host}/asset-manifest.json`)
18 | .then((res) => res.json())
19 | .then((manifest) => {
20 | const script = document.createElement("script");
21 | script.id = scriptId;
22 | script.crossOrigin = "";
23 | script.src = `${host}${manifest.files["main.js"]}`;
24 | script.onload = () => {
25 | renderMicroFrontend();
26 | };
27 | document.head.appendChild(script);
28 | });
29 |
30 | return () => {
31 | window[`unmountForm`] && window[`unmountForm`](`Form-container`);
32 | };
33 | });
34 |
35 | return ;
36 | };
37 |
38 | MicroFrontend.defaultProps = {
39 | document,
40 | window,
41 | };
42 |
--------------------------------------------------------------------------------
/day5-microfrontend/host2/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
12 | monospace;
13 | }
14 |
15 | .container {
16 | margin-top: 1rem;
17 | }
18 |
--------------------------------------------------------------------------------
/day5-microfrontend/host2/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | const root = ReactDOM.createRoot(document.getElementById('root'));
8 | root.render(
9 |
10 |
11 |
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
--------------------------------------------------------------------------------
/day5-microfrontend/host2/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/day5-microfrontend/host2/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/day5-microfrontend/host2/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/day6-price-drop-alert/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Price Tracker and Email Notifier
3 |
4 | This project scrapes the price of a product from an e-commerce website using Puppeteer and sends an email notification when the price drops below a specified threshold. The script is scheduled to run every minute using the Node Schedule library.
5 |
6 | ## Features
7 |
8 | - Scrapes product title and price from a given URL.
9 | - Compares the price with a specified threshold.
10 | - Sends an email notification when the price drops below the threshold.
11 | - Uses Puppeteer for web scraping and MailerSend for sending emails.
12 | - Automates the price check every minute with Node Schedule.
13 |
14 | ## Prerequisites
15 |
16 | Make sure you have the following installed:
17 |
18 | - [Node.js](https://nodejs.org/en/download/) (version 12 or higher)
19 | - An active MailerSend account and API key.
20 |
21 | ## Setup Instructions
22 |
23 | Follow these steps to set up the project locally.
24 |
25 | ### 1. Clone the repository
26 |
27 | ```bash
28 | git clone https://github.com/codewithayaann/Machine-Round-Challenge.git
29 | cd day6-price-drop-alert
30 | ```
31 |
32 | ### 2. Install dependencies
33 |
34 | Install the required Node.js packages by running:
35 |
36 | ```bash
37 | npm install puppeteer node-schedule mailersend
38 | ```
39 |
40 | ### 3. Configure the script
41 |
42 | - Open the `index.js` file.
43 | - Replace the `apiKey` and `from email` with your MailerSend API key and sender details.
44 |
45 | ```javascript
46 | const mailerSend = new MailerSend({
47 | apiKey: "YOUR_API_KEY",
48 | });
49 | ```
50 |
51 | - Update the `url` variable with the product URL you want to track and set your desired `thresholdPrice`:
52 |
53 | ```javascript
54 | const url = 'https://www.flipkart.com/your-product-url';
55 | const threasholdPrice = 110_000;
56 | ```
57 |
58 | ### 4. Run the Script
59 |
60 | You can run the script manually by executing:
61 |
62 | ```bash
63 | node index.js
64 | ```
65 |
66 | ### 5. Set Up Scheduled Price Checks
67 |
68 | The script is already scheduled to run every minute using the Node Schedule library. To adjust the frequency, update the cron-like expression in this line:
69 |
70 | ```javascript
71 | schedule.scheduleJob('*/1 * * * *', async () => {
72 | // your price tracking logic here
73 | });
74 | ```
75 |
76 | - `*/1` indicates the script will run every minute. You can adjust it as needed.
77 |
78 | ## How It Works
79 |
80 | 1. **Puppeteer** is used to launch a browser instance and visit the product page.
81 | 2. **Web Scraping**: It retrieves the product title and price by selecting specific HTML elements.
82 | 3. **Price Comparison**: It checks whether the current price is below a set threshold.
83 | 4. **Email Notification**: If the price drops below the threshold, it triggers an email using the MailerSend API with the product link.
84 | 5. **Scheduler**: The `Node Schedule` library ensures that the price check runs at regular intervals (e.g., every minute).
85 |
86 | ## Output
87 |
88 | - If the price is lower than the threshold, an email like the one below is sent:
89 |
90 | ```
91 | Subject: Price Drop
92 | Message: Price has been dropped to ₹100,000.
93 | Link to purchase: https://www.flipkart.com/your-product-url
94 | ```
95 |
--------------------------------------------------------------------------------
/day6-price-drop-alert/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "day6-price-drop-alert",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "server.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "nodemon server.js"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "init": "^0.1.2",
14 | "mailersend": "^2.3.0",
15 | "mailsender": "^1.1.2",
16 | "node-schedule": "^2.1.1",
17 | "nodemon": "^3.1.4",
18 | "npm": "^10.8.3",
19 | "puppeteer": "^23.3.0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/day6-price-drop-alert/server.js:
--------------------------------------------------------------------------------
1 | const puppeteer = require('puppeteer');
2 | const schedule = require("node-schedule");
3 |
4 | const { MailerSend, EmailParams, Sender, Recipient } = require("mailersend");
5 |
6 | const getTitleAndPrice = async (url) => {
7 | const browser = await puppeteer.launch()
8 | const page = await browser.newPage()
9 | await page.goto(url)
10 |
11 | return page.evaluate(() => {
12 | const title = document.querySelector('.VU-ZEz')?.textContent;
13 | const price = document.querySelector('.CxhGGd')?.textContent;
14 | return {
15 | title,
16 | price
17 | }
18 | })
19 | }
20 |
21 | const comparePrice = (currentPrice, threasholdPrice, url) => {
22 | const price = +currentPrice.slice(1).split(",").join("");
23 | if (price < threasholdPrice) {
24 | // email
25 | const mailerSend = new MailerSend({
26 | apiKey: "YOUR_API_KEY",
27 | });
28 |
29 | const sentFrom = new Sender("MS_mUENVf@trial-v69oxl5kp1kl785k.mlsender.net", "TRIAL");
30 |
31 | const recipients = [
32 | new Recipient("codewithayaan01@gmail.com", "Ayaan")
33 | ];
34 |
35 |
36 | const emailParams = new EmailParams()
37 | .setFrom(sentFrom)
38 | .setTo(recipients)
39 | .setSubject("Price Drop")
40 | .setHtml(`Price has been dropped to ${currentPrice}
41 | Link to purchase
42 | `)
43 |
44 | mailerSend.email
45 | .send(emailParams)
46 | .then((response) => console.log(response))
47 | .catch((error) => console.log(error));
48 | console.log("Yohuuu, Amount reduced please purchase your product")
49 | }
50 | }
51 |
52 | schedule.scheduleJob('*/1 * * * *', async () => {
53 | const url = 'https://www.flipkart.com/apple-2020-macbook-air-m1-16-gb-256-gb-ssd-mac-os-big-sur-mgn63hn-a/p/itm81ebc91ac5348?pid=COMH2SZFDTJZFD94&lid=LSTCOMH2SZFDTJZFD94Z0M86Y&marketplace=FLIPKART&q=macbook&store=6bo%2Fb5g&srno=s_1_2&otracker=search&otracker1=search&fm=organic&iid=b821bbba-8294-4af7-914e-97dc5e0768d5.COMH2SZFDTJZFD94.SEARCH&ppt=pp&ppn=pp&ssid=uzbeestcqo0000001726382933326&qH=864faee128623e2f'
54 | const { price } = await getTitleAndPrice(url)
55 | const threasholdPrice = 110_000;
56 | comparePrice(price, threasholdPrice, url)
57 | })
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/README.md:
--------------------------------------------------------------------------------
1 |
2 | **utils:**
3 |
4 |
5 | ```javascript
6 | export function addItem(trees, parentId, newItem) {
7 | return trees.map((node) => {
8 | if (node.id === parentId && node.type === 'folder') {
9 | return {
10 | ...node,
11 | children: [...(node.children || []), newItem]
12 | }
13 | } else if (node.children) {
14 | return {
15 | ...node,
16 | children: addItem(node.children, parentId, newItem)
17 | }
18 | }
19 | return node;
20 | })
21 | }
22 |
23 |
24 | export function deleteNode(trees, nodeId) {
25 | return trees.map((node) => {
26 | if (node.children) {
27 | return {
28 | ...node,
29 | children: deleteNode(node.children, nodeId)
30 | }
31 | }
32 | return node;
33 | }).filter(node => node.id !== nodeId)
34 | }
35 |
36 |
37 |
38 | ```
39 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "day07-folder-file-structure-like-vs-code",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.17.0",
7 | "@testing-library/react": "^13.4.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "react": "^18.3.1",
10 | "react-dom": "^18.3.1",
11 | "react-scripts": "5.0.1",
12 | "web-vitals": "^2.1.4"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test",
18 | "eject": "react-scripts eject"
19 | },
20 | "eslintConfig": {
21 | "extends": [
22 | "react-app",
23 | "react-app/jest"
24 | ]
25 | },
26 | "browserslist": {
27 | "production": [
28 | ">0.2%",
29 | "not dead",
30 | "not op_mini all"
31 | ],
32 | "development": [
33 | "last 1 chrome version",
34 | "last 1 firefox version",
35 | "last 1 safari version"
36 | ]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day7-folder-file-structure-like-vs-code/public/favicon.ico
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 | You need to enable JavaScript to run this app.
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day7-folder-file-structure-like-vs-code/public/logo192.png
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codewithayaann/Machine-Round-Challenge/14cc988958feb1bf870a5d72f964bfc6d9afce0a/day7-folder-file-structure-like-vs-code/public/logo512.png
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | padding: 20px;
3 | }
4 |
5 | .folder {
6 | margin-left: 20px;
7 | }
8 |
9 | .d-flex {
10 | display: flex;
11 | }
12 |
13 | .delete {
14 | color: red;
15 | }
16 |
17 | .folder-section {
18 | cursor: pointer;
19 | }
20 |
21 | .folder-section .buttons {
22 | display: none;
23 | }
24 |
25 | .folder-section:hover .buttons {
26 | display: block;
27 | cursor: pointer;
28 | }
29 |
30 |
31 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/src/App.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import './App.css';
3 | import { FileTree } from './FileTree';
4 | import { addItem, deleteNode } from './utils';
5 |
6 |
7 | const initialData = [
8 | {
9 | id: "1",
10 | type: "folder",
11 | name: "src",
12 | children: [
13 | { id: "2", type: "file", name: "index.js" },
14 | {
15 | id: "3",
16 | type: "folder",
17 | name: "components",
18 | children: [
19 | { id: "4", type: "file", name: "Header.js" },
20 | { id: "5", type: "file", name: "Footer.js" },
21 | ],
22 | },
23 | ],
24 | },
25 | { id: "6", type: "file", name: "README.md" },
26 | ];
27 |
28 |
29 | function App() {
30 | const [structure, setStructure] = useState(() => initialData)
31 | const [parentIdType, setParentIdType] = useState({
32 | parentId: null,
33 | type: ''
34 | })
35 | const [fileFolderName, setFileFolderName] = useState('')
36 |
37 |
38 |
39 |
40 | const handleAdd = (parentId, type) => {
41 | setParentIdType({
42 | parentId,
43 | type
44 | })
45 | }
46 |
47 | const onDelete = (nodeId) => {
48 | setStructure((prev) => deleteNode(prev, nodeId))
49 | }
50 |
51 | const onFileFolderSave = (event) => {
52 | if (event.key === 'Enter') {
53 | const newItem = {
54 | id: new Date().getTime(),
55 | name: fileFolderName,
56 | type: parentIdType.type,
57 | ...(parentIdType.type === 'folder' && {
58 | children: []
59 | })
60 | }
61 | setStructure(prev => addItem(prev, parentIdType.parentId, newItem))
62 | setParentIdType({
63 | parentId: null,
64 | type: ''
65 | })
66 | setFileFolderName('')
67 | }
68 | }
69 |
70 |
71 | return (
72 |
73 |
82 |
83 | );
84 | }
85 |
86 | export default App;
87 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render( );
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/src/FileTree.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Folder } from './Folder'
3 |
4 | export const FileTree = ({
5 | structure,
6 | fileFolderName,
7 | setFileFolderName,
8 | onFileFolderSave,
9 | handleAdd,
10 | parentIdType,
11 | onDelete
12 | }) => {
13 | return structure.map((node) => {
14 | return (
15 |
16 |
25 | {Array.isArray(node.children) &&
26 |
37 | }
38 |
)
39 | })
40 | }
41 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/src/Folder.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react'
2 |
3 | export const Folder = ({
4 | node,
5 | fileFolderName,
6 | setFileFolderName,
7 | onFileFolderSave,
8 | handleAdd,
9 | parentIdType,
10 | onDelete
11 | }) => {
12 | return (
13 |
34 | )
35 | }
36 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | const root = ReactDOM.createRoot(document.getElementById('root'));
8 | root.render(
9 |
10 |
11 |
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/day7-folder-file-structure-like-vs-code/src/utils.js:
--------------------------------------------------------------------------------
1 | export function addItem(trees, parentId, newItem) {
2 | return trees.map((node) => {
3 | if (node.id === parentId && node.type === 'folder') {
4 | return {
5 | ...node,
6 | children: [...(node.children || []), newItem]
7 | }
8 | } else if (node.children) {
9 | return {
10 | ...node,
11 | children: addItem(node.children, parentId, newItem)
12 | }
13 | }
14 | return node;
15 | })
16 | }
17 |
18 |
19 | export function deleteNode(trees, nodeId) {
20 | return trees.map((node) => {
21 | if (node.children) {
22 | return {
23 | ...node,
24 | children: deleteNode(node.children, nodeId)
25 | }
26 | }
27 | return node;
28 | }).filter(node => node.id !== nodeId)
29 | }
30 |
31 |
--------------------------------------------------------------------------------