Advertisement
amt

Cart

amt
Oct 22nd, 2024 (edited)
154
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { useEffect, useState } from "react";
  2. import { Box } from "@mui/material";
  3.  
  4. export default function Cart() {
  5.  
  6.     const [items, setItems] = useState(["Book 1", "Book 2"]);
  7.     const [quantities, setQuantities] = useState({});
  8.     const [cart, setCart] = useState([]);
  9.  
  10.  
  11.  
  12.     useEffect(() => {
  13.         console.log("quantities", quantities);
  14.     }, [quantities]);
  15.  
  16.     useEffect(() => {
  17.         console.log("cart", cart);
  18.     }, [cart]);
  19.  
  20.  
  21.     const addToCart = (item, quantity = 1) => {
  22.         console.log(item, quantity);
  23.  
  24.         const index = cart.findIndex(cartItem => cartItem.name === item);
  25.  
  26.         let newCart = [...cart];
  27.  
  28.         if (index > -1) {
  29.             newCart.splice(index, 1, { ...newCart[index], quantity: newCart[index]["quantity"] + quantity });
  30.  
  31.             // newCart = [
  32.             //     ...newCart.slice(0, index),
  33.             //     { ...newCart[index], quantity: newCart[index]["quantity"] + quantity },
  34.             //     ...newCart.slice(index + 1)
  35.             // ];
  36.         } else {
  37.             newCart = [...newCart, { name: item, quantity: quantity }]
  38.         }
  39.  
  40.         setCart(newCart);
  41.     }
  42.  
  43.     return (
  44.         <div style={{display: "flex", justifyContent: "center", alignItems: "center", height: "80vh"}}>
  45.             <div
  46.             // style={{ alignContent: "center"}}
  47.             >
  48.             {
  49.                 items.map(item => <div key={`item$${item}`}
  50.                     // style={{ display: "flex", alignItems: "center", height: "400px"}}
  51.                 >
  52.                     <label>{item}</label>
  53.                     <input type="number" value={quantities[item] ? parseInt(quantities[item]) : 1} onChange={e => setQuantities({ ...quantities, [item]: parseInt(e.target.value) })} />
  54.                     <button onClick={() => addToCart(item, quantities[item])}>{"Add to cart"}</button>
  55.                 </div>)
  56.             }
  57.             </div>
  58.         </div>
  59.  
  60.         // <div>
  61.         //     {
  62.         //         items.map(item => (
  63.         //             <div key={item}>
  64.         //                 <label>{item}</label>
  65.         //                 <input
  66.         //                     type="number"
  67.         //                     value={quantities[item] !== undefined ? quantities[item] : 0}
  68.         //                     onChange={e => {
  69.         //                         let value = e.target.value;
  70.  
  71.         //                         // Use regex to remove leading zeros
  72.         //                         let cleanedValue = value.replace(/^0+(?=\d)/, '');
  73.  
  74.         //                         // Handle empty input
  75.         //                         setQuantities({ ...quantities, [item]: cleanedValue === '' ? '' : cleanedValue });
  76.         //                     }}
  77.         //                 />
  78.         //             </div>
  79.         //         ))
  80.         //     }
  81.         // </div>
  82.  
  83.     );
  84. }
  85.  
  86.  
  87.  
  88. import React, { useEffect, useState } from 'react';
  89.  
  90. function List(props) {
  91.   const [list, setList] = useState([
  92.     { n: 'diary', s: 5 },
  93.     { n: 'hat', s: 3 },
  94.   ]);
  95.   const [cart, setCart] = useState([]);
  96.  
  97.   const add = (item, qty = 1) => {
  98.     const newC = [...cart];
  99.  
  100.     const ind = newC.findIndex((c) => c.n == item);
  101.  
  102.     if (ind > -1) {
  103.       newC.splice(ind, 1, { n: item, s: newC[ind].s + qty });
  104.       setCart(newC);
  105.     } else {
  106.       setCart([...newC, { n: item, s: qty }]);
  107.     }
  108.   };
  109.  
  110.   const remove = (item, qty = 1) => {
  111.     const newC = [...cart];
  112.  
  113.     const ind = newC.findIndex((c) => c.n == item);
  114.  
  115.     if (newC[ind].s > 1) {
  116.       newC.splice(ind, 1, { n: item, s: newC[ind].s - qty });
  117.       setCart(newC);
  118.     } else {
  119.       setCart(newC.filter((c) => c.n !== item));
  120.     }
  121.   };
  122.  
  123.   useEffect(() => {
  124.     console.log(cart);
  125.   }, [cart]);
  126.   return (
  127.     <div
  128.       style={{
  129.         display: 'flex',
  130.         flexDirection: 'row',
  131.         justifyContent: 'space-between',
  132.       }}
  133.     >
  134.       <div
  135.         style={{
  136.           display: 'flex',
  137.           flexDirection: 'column',
  138.           justifyContent: 'space-between',
  139.         }}
  140.       >
  141.         {list.map((item) => (
  142.           <div style={{ display: 'flex', flexDirection: 'row' }}>
  143.             <div>{item.n}</div>
  144.             <button
  145.               disabled={
  146.                 item.s < 1 || cart?.filter((c) => c.n == item.n)[0]?.s == item.s
  147.               }
  148.               onClick={() => add(item.n)}
  149.             >
  150.               {'+'}
  151.             </button>
  152.           </div>
  153.         ))}
  154.       </div>
  155.       <div
  156.         style={{
  157.           display: 'flex',
  158.           flexDirection: 'column',
  159.           justifyContent: 'space-between',
  160.         }}
  161.       >
  162.         {cart?.map((item) => (
  163.           <div style={{ display: 'flex', flexDirection: 'row' }}>
  164.             <div>{`${item.n}: ${item.s}`}</div>
  165.             <button onClick={() => remove(item.n)}>{'-'}</button>
  166.           </div>
  167.         ))}
  168.       </div>
  169.     </div>
  170.   );
  171. }
  172. export default List;
  173.  
  174.  
  175.  
  176.  
  177.  
  178. import React from 'react';
  179.  
  180. const PageComponent = React.memo(({ data }) => {
  181.     return (
  182.         <div>
  183.             {data}
  184.         </div>
  185.     );
  186. });
  187.  
  188. const App = () => {
  189.     const [pages, setPages] = useState([]);
  190.  
  191.     const handleLoadMore = () => {
  192.         // Fetch more data and update the pages state
  193.     };
  194.  
  195.     return (
  196.         <div>
  197.             {pages.map((page, index) => (
  198.                 <PageComponent key={index} data={page} />
  199.             ))}
  200.             <button onClick={handleLoadMore}>Load More</button>
  201.         </div>
  202.     );
  203. };
  204.  
  205.  
  206.  
  207. import { useEffect, useState } from "react";
  208. import { Box } from "@mui/material";
  209.  
  210.  
  211.  
  212. const PageComponent = React.memo( ({ data }) => {
  213.     return (
  214.         <div>
  215.             {/* Render page content using data */}
  216.         </div>
  217.     );
  218. });
  219.  
  220.  
  221.  
  222. export default function Solution() {
  223.  
  224.     const [data, setData] = useState([]);
  225.     const [dataWithImages, setDataWithImages] = useState([]);
  226.     const [error, setError] = useState('');
  227.     const [loading, setLoading] = useState(true);
  228.     const [hoverIndex, setHoverIndex] = useState(null);
  229.  
  230.     const fetchData = async (url) => {
  231.         try {
  232.             const response = await fetch(url);
  233.             if (!response.ok) {
  234.                 throw new Error(`Response status: ${response.status}`);
  235.             }
  236.             const data = await response.json();
  237.             return data;
  238.         } catch (error) {
  239.             setError(error);
  240.         } finally {
  241.             setLoading(false);
  242.         }
  243.     };
  244.  
  245.     const fetchAllData = async (items) => {
  246.         try {
  247.             const promises = items?.map((item) =>
  248.                 fetchData(`https://dog.ceo/api/breed/${item}/images/random`)
  249.             );
  250.             const imagesData = await Promise.all(promises);
  251.             return imagesData;
  252.         } catch (error) {
  253.             setError(error);
  254.         }
  255.     };
  256.  
  257.     useEffect(() => {
  258.         fetchData('https://dog.ceo/api/breeds/list/all').then((data) => {
  259.             setData(data.message);
  260.             fetchAllData(Object.keys(data?.message)).then((dataArray) => {
  261.                 setDataWithImages(dataArray);
  262.                 setLoading(false);
  263.             });
  264.         });
  265.     }, []);
  266.  
  267.     return (
  268.         <>
  269.             {loading && <div id={'js_loading'}>{'Loading'}</div>}
  270.             {!loading && data && dataWithImages && (
  271.                 <div style={{ display: 'flex', flexWrap: 'wrap' }} id={'js_gallery'}>
  272.                     {dataWithImages &&
  273.                         Array.isArray(dataWithImages) &&
  274.                         dataWithImages.map((imgObj, index) => (
  275.                             <div
  276.                                 style={{ position: 'relative', maxHeight: '200px' }}
  277.                                 id={'js_gallery'}
  278.                                 onMouseEnter={() => setHoverIndex(index)}
  279.                                 onMouseLeave={() => setHoverIndex(null)}
  280.                             >
  281.                                 <img
  282.                                     src={imgObj.message}
  283.                                     style={{ maxHeight: '200px', objectFit: 'cover' }}
  284.                                     className={'js_image'}
  285.                                 />
  286.                                 <div
  287.                                     className={'js_name'}
  288.                                     style={{
  289.                                         position: 'absolute',
  290.                                         left: '10px',
  291.                                         bottom: '10px',
  292.                                         zIndex: 400,
  293.                                         color: 'white',
  294.                                         textShadow: '2px 2px 5px black',
  295.                                         opacity: hoverIndex == index ? 1 : 0,
  296.                                     }}
  297.                                     id={'js_gallery'}
  298.                                 >
  299.                                     {Object.keys(data)[index]
  300.                                         ? Object.keys(data)[index]?.charAt(0)?.toUpperCase() +
  301.                                         Object.keys(data)[index]?.slice(1)
  302.                                         : 'Good Dog'}
  303.                                 </div>
  304.                             </div>
  305.                         ))}
  306.                 </div>
  307.             )}
  308.         </>
  309.     );
  310. }
  311.  
  312.  
  313.  
  314.  
  315.  
  316.  
  317. import React, { useEffect, useState } from "react";
  318. import IconButton from '@mui/material/IconButton';
  319. import DeleteIcon from '@mui/icons-material/Delete';
  320.  
  321. export default function Solution() {
  322.  
  323.   const [data, setData] = React.useState([]);
  324.   const [error, setError] = React.useState('');
  325.   const [deleteError, setDeleteError] = React.useState('');
  326.   const [token, setToken] = React.useState(typeof window !== 'undefined' ? localStorage.getItem('token') : null);
  327.  
  328.   const fetchData = async (url) => {
  329.     try {
  330.       const response = await fetch(url);
  331.       if (!response.ok) {
  332.         throw new Error();
  333.       }
  334.       const data = await response.json();
  335.       setData(data);
  336.     } catch (error) {
  337.       setError(error);
  338.     }
  339.   };
  340.  
  341.   const deleteData = async (id) => {
  342.     try {
  343.       const response = await fetch(
  344.         'https://api.sampleapis.com/countries/countries',
  345.         {
  346.           method: 'POST',
  347.           headers: {
  348.             // Accept: 'application/json',
  349.             'Content-Type': 'application/json',
  350.             'Authorization': `Bearer ${token}`,
  351.           },
  352.           body: JSON.stringify({ id: id }),
  353.         }
  354.       );
  355.       const data = await response.json();
  356.       if (data.error != 200) {
  357.         setDeleteError(data.message);
  358.       }
  359.       console.log(data);
  360.     } catch (error) {
  361.       setError(error);
  362.     }
  363.   };
  364.  
  365.   React.useEffect(() => {
  366.     fetchData('https://api.sampleapis.com/countries/countries');
  367.     setToken(localStorage.getItem('token'));
  368.   }, []);
  369.  
  370.   const deleteCountry = (id) => {
  371.     deleteData(id);
  372.   };
  373.  
  374.   return (
  375.     <div>
  376.       <h1 style={{margin: "20px 0"}}>Countries</h1>
  377.       <h5 style={{ color: 'red', fontWeight: "300", margin: "20px 0" }}>{deleteError}</h5>
  378.  
  379.       <table
  380.         // border={13}
  381.         // cellPadding={5}
  382.         // cellSpacing={1}
  383.         // style={{ borderColor: '#fefefe', borderCollapse: "collapse" }}
  384.       >
  385.         <thead>
  386.           <tr>
  387.             <th>ID</th>
  388.             <th>Name</th>
  389.             <th>Currency</th>
  390.             <th>Capital</th>
  391.             <th>Action</th>
  392.           </tr>
  393.         </thead>
  394.         <tbody>
  395.           {data &&
  396.             Array.isArray(data) &&
  397.             data.map((country) => (
  398.               <tr key={country.id}>
  399.                 <td>{country.id}</td>
  400.                 <td>{country.name}</td>
  401.                 <td>{country.currency}</td>
  402.                 <td>{country.capital}</td>
  403.                 <td>
  404.                   <IconButton aria-label="delete" onClick={() => deleteCountry(country.id)}>
  405.                     <DeleteIcon />
  406.                   </IconButton>
  407.                 </td>
  408.               </tr>
  409.             ))}
  410.         </tbody>
  411.       </table>
  412.     </div>
  413.   );
  414. }
  415.  
  416.  
  417.  
  418.  
  419. import { useEffect, useState } from "react";
  420. import { Box } from "@mui/material";
  421.  
  422. export default function Solution() {
  423.  
  424.     const [searchTerm, setSearchTerm] = useState("");
  425.     const [data, setData] = useState(null);
  426.     const [loading, setLoading] = useState(true);
  427.     const [error, setError] = useState(null);
  428.     const [similar, setSimilar] = useState(null);
  429.  
  430.     const fetchData = async (url) => {
  431.         try {
  432.             const response = await fetch(url);
  433.             if (!response.ok) {
  434.                 throw new Error();
  435.             }
  436.             const data = await response.json();
  437.             return data;
  438.         } catch (error) {
  439.             setError(error);
  440.         } finally {
  441.             setLoading(false);
  442.         }
  443.     };
  444.  
  445.  
  446.     // debounce
  447.     useEffect(() => {
  448.         const timeoutId = setTimeout(() => {
  449.             fetchData('https://api.sampleapis.com/coffee/hot')
  450.                 .then(result => setData(result && Array.isArray(result) && result.filter((item) => item?.title?.toLowerCase().includes(searchTerm?.toLowerCase()))))
  451.         }, 2000);
  452.         return () => clearTimeout(timeoutId);
  453.     }, [searchTerm]);
  454.  
  455.  
  456.     const handleSearch = (e) => {
  457.         setLoading(true);
  458.         setSimilar(null);
  459.         e.preventDefault();
  460.         setSearchTerm(e.target.value);
  461.     }
  462.  
  463.     const handleSuggestionClick = () => {
  464.         fetchData('https://api.sampleapis.com/coffee/iced')
  465.             .then(result => setSimilar(result && Array.isArray(result) ? result : []))
  466.     }
  467.  
  468.     return (
  469.         <Box>
  470.             <div style={{ marginBottom: "5px" }}>Search Coffee Type (Ex: latte)</div>
  471.             <input
  472.                 type="text"
  473.                 value={searchTerm}
  474.                 onChange={handleSearch}
  475.                 style={{
  476.                     width: "100%",
  477.                     border: "1px solid #d1d1d1",
  478.                     padding: "8px"
  479.                 }}
  480.             />
  481.             {loading &&
  482.                 <div style={{ margin: "5px 0" }}>Loading Suggestions...</div>
  483.             }
  484.             {
  485.                 !loading && !similar && data && Array.isArray(data) && data.map((item) => (
  486.                     <div
  487.                         key={item?.title}
  488.                         style={{
  489.                             marginTop: "3px",
  490.                             marginBottom: "3px",
  491.                             padding: "4px",
  492.                             background: "#f4f4f4",
  493.                             cursor: "pointer",
  494.                         }}
  495.                         onClick={handleSuggestionClick}
  496.                     >{item?.title}</div>
  497.                 ))
  498.             }
  499.             {similar && Array.isArray(similar) &&
  500.                 <>
  501.                     <div style={{ margin: "5px 0" }}>Similar Iced Coffee:</div>
  502.                     <div style={{ display: 'flex', flexWrap: 'wrap', marginTop: "3px", marginBottom: "3px", }}>
  503.                         {
  504.  
  505.                             similar.map((item, index) => (
  506.                                 <div
  507.                                     style={{ position: 'relative', maxHeight: '200px' }}
  508.                                     id={'js_gallery'}
  509.                                     key={`js_gallery${index}`}
  510.                                 >
  511.                                     <img
  512.                                         src={item.image}
  513.                                         style={{ maxHeight: '200px', objectFit: 'cover' }}
  514.                                         className={'js_image'}
  515.                                     />
  516.                                     <div
  517.                                         className={'js_name'}
  518.                                         style={{
  519.                                             position: 'absolute',
  520.                                             left: '10px',
  521.                                             bottom: '10px',
  522.                                             zIndex: 400,
  523.                                             color: 'white',
  524.                                             textShadow: '2px 2px 5px black',
  525.                                             opacity: 1,
  526.                                         }}
  527.                                         id={'js_gallery'}
  528.                                     >
  529.                                         {item.title
  530.                                             ? item.title
  531.                                             : 'Iced Coffee'}
  532.                                     </div>
  533.                                 </div>
  534.                             ))
  535.                         }
  536.                     </div>
  537.                 </>
  538.             }
  539.         </Box>
  540.     );
  541. }
  542.  
  543.  
  544.  
  545.  
  546. import { useEffect, useRef, useState, useCallback } from "react";
  547. import TypewriterLetter from "./TypewriterLetter";
  548.  
  549. // This is considered a failure code response :)
  550.  
  551. // this allows us to filter out nodes that
  552. // don't follow the pattern in O(1) notation
  553. const depthMap = {
  554.   0: "BODY",
  555.   1: "CODE",
  556.   2: "DIV",
  557.   3: "SPAN",
  558.   4: "I"
  559. };
  560.  
  561. export default function App() {
  562.   // use a ref here so we don't re-render every time
  563.   // we iterate through the tree
  564.   const url = useRef("");
  565.   const [secretUrl, setSecretUrl] = useState("");
  566.   const [secretCode, setSecretCode] = useState("");
  567.  
  568.   // Standard DFS search, in order
  569.   const searchTree = useCallback((node, currentDepth) => {
  570.     const children = node.children;
  571.     const nodeType = node.nodeName;
  572.  
  573.     // quick check to filter out improper no types at depth
  574.     // or if anything is greater than the max depth for our pattern
  575.     if (nodeType !== depthMap[currentDepth] || currentDepth > 4) {
  576.       return;
  577.     }
  578.  
  579.     if (children.length === 0 && node.getAttribute("value")) {
  580.       url.current += node.getAttribute("value");
  581.       return;
  582.     } else if (children.length === 0) {
  583.       return;
  584.     }
  585.  
  586.     for (let i = 0; i < children.length; i++) {
  587.       searchTree(children[i], currentDepth + 1);
  588.     }
  589.   }, []);
  590.  
  591.   const fetchHtml = useCallback(async () => {
  592.     const htmlResponse = await fetch(
  593.       "https://tns4lpgmziiypnxxzel5ss5nyu0nftol.lambda-url.us-east-1.on.aws/challenge"
  594.     );
  595.     const html = await htmlResponse.text();
  596.  
  597.     // Use standard web api so we don't have to build our own tree
  598.     const docToParse = new DOMParser().parseFromString(html, "text/html");
  599.     const root = docToParse.body;
  600.  
  601.     searchTree(root, 0);
  602.     setSecretUrl(url.current);
  603.     url.current = "";
  604.   }, [searchTree]);
  605.  
  606.   const fetchSecretCode = useCallback(async () => {
  607.     if (!secretUrl) {
  608.       return;
  609.     }
  610.     const secretCode = await fetch(secretUrl).then((result) => result.text());
  611.  
  612.     setSecretCode(secretCode);
  613.   }, [secretUrl]);
  614.  
  615.   useEffect(() => {
  616.     fetchHtml();
  617.   }, [fetchHtml]);
  618.  
  619.   useEffect(() => {
  620.     fetchSecretCode();
  621.   }, [fetchSecretCode]);
  622.  
  623.   return (
  624.     <div className="App">
  625.       <h1>Capture The Flag</h1>
  626.       <div className="letterContainer">
  627.         {secretCode ? (
  628.           secretCode.split("").map((letter, index) => (
  629.             <TypewriterLetter key={letter} delay={index}>
  630.               {letter}
  631.             </TypewriterLetter>
  632.           ))
  633.         ) : (
  634.           <p>Loading...</p>
  635.         )}
  636.       </div>
  637.     </div>
  638.   );
  639. }
  640.  
  641.  
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653. import React, { useState, useEffect, useRef, useCallback } from "react";
  654. import "./styles.css";
  655.  
  656. const InfiniteScroll = () => {
  657.   const [items, setItems] = useState(Array.from({ length: 20 }));
  658.   const [hasMore, setHasMore] = useState(true);
  659.   const loaderRef = useRef(null);
  660.  
  661.   // Mock function to simulate data fetching
  662.   const fetchMoreItems = () => {
  663.     setTimeout(() => {
  664.       setItems((prevItems) => [
  665.         ...prevItems,
  666.         ...Array.from({ length: 20 }) // Add 20 more items
  667.       ]);
  668.     }, 1000);
  669.   };
  670.  
  671.   // Intersection Observer to trigger loading more items
  672.   const handleObserver = useCallback((entries) => {
  673.     const target = entries[0];
  674.     if (target.isIntersecting && hasMore) {
  675.       fetchMoreItems();
  676.     }
  677.   }, [hasMore]);
  678.  
  679.   useEffect(() => {
  680.     const option = {
  681.       root: null,
  682.       rootMargin: "20px",
  683.       threshold: 0.5
  684.     };
  685.  
  686.     const observer = new IntersectionObserver(handleObserver, option);
  687.     if (loaderRef.current) observer.observe(loaderRef.current);
  688.  
  689.     return () => observer.disconnect();
  690.   }, [handleObserver]);
  691.  
  692.   return (
  693.     <div className="infinite-scroll-container">
  694.       <h1>Infinite Scroll Component</h1>
  695.       <ul className="item-list">
  696.         {items.map((_, index) => (
  697.           <li key={index} className="item">
  698.             Item {index + 1}
  699.           </li>
  700.         ))}
  701.       </ul>
  702.       <div ref={loaderRef} className="loading">
  703.         {hasMore ? "Loading more items..." : "No more items to load"}
  704.       </div>
  705.     </div>
  706.   );
  707. };
  708.  
  709. export default InfiniteScroll;
  710.  
  711.  
  712.  
  713.  
  714. import React, { useState } from "react";
  715.  
  716. // Sample Directory Structure (No 'type' field)
  717. const directoryData = {
  718.   name: "root",
  719.   children: [
  720.     {
  721.       name: "Documents",
  722.       children: [
  723.         { name: "Resume.pdf" },
  724.         { name: "CoverLetter.docx" }
  725.       ]
  726.     },
  727.     {
  728.       name: "Pictures",
  729.       children: [{ name: "Vacation.jpg" }]
  730.     },
  731.     { name: "notes.txt" }
  732.   ]
  733. };
  734.  
  735. // Recursive Component to Render Directory
  736. const Directory = ({ data }) => {
  737.   const [expanded, setExpanded] = useState(false);
  738.  
  739.   // Check if this is a folder (has children)
  740.   const isFolder = Object.hasOwn(data, 'children');
  741.  
  742.   // Toggle folder expansion
  743.   const handleToggle = () => {
  744.     if (isFolder) {
  745.       setExpanded(!expanded);
  746.     }
  747.   };
  748.  
  749.   return (
  750.     <div style={{ marginLeft: "20px" }}>
  751.       <div
  752.         onClick={handleToggle}
  753.         style={{ cursor: isFolder ? "pointer" : "default" }}
  754.       >
  755.         {isFolder ? (expanded ? "\u{1F4C2}" : "\u{1F4C1}") : "\u{1F4C4}"} {data.name}
  756.       </div>
  757.  
  758.       {expanded && isFolder && (
  759.         <div style={{ marginLeft: "20px" }}>
  760.           {data.children.map((child, index) => (
  761.             <Directory key={index} data={child} />
  762.           ))}
  763.         </div>
  764.       )}
  765.     </div>
  766.   );
  767. };
  768.  
  769. // Main App Component
  770. const App = () => {
  771.   return (
  772.     <div>
  773.       <h2>File Explorer</h2>
  774.       <Directory data={directoryData} />
  775.     </div>
  776.   );
  777. };
  778.  
  779. export default App;
  780.  
  781.  
  782.  
  783.  
  784. import React, { useState } from "react";
  785.  
  786. // Sample Directory Structure
  787. const directoryData = {
  788.   name: "root",
  789.   children: [
  790.     {
  791.       name: "Documents",
  792.       children: [
  793.         { name: "Resume.pdf" },
  794.         { name: "CoverLetter.docx" }
  795.       ]
  796.     },
  797.     {
  798.       name: "Pictures",
  799.       children: [{ name: "Vacation.jpg" }]
  800.     },
  801.     { name: "notes.txt" }
  802.   ]
  803. };
  804.  
  805. // Recursive Component to Render Directory
  806. const Directory = ({ data, isLast = false, level = 0, hasSiblingsAbove = false }) => {
  807.   const [expanded, setExpanded] = useState(false);
  808.  
  809.   // Check if this is a folder (has children)
  810.   const isFolder = Object.hasOwn(data, 'children');
  811.  
  812.   // Toggle folder expansion
  813.   const handleToggle = () => {
  814.     if (isFolder) {
  815.       setExpanded(!expanded);
  816.     }
  817.   };
  818.  
  819.   return (
  820.     <div style={{ position: "relative", marginLeft: level > 0 ? "20px" : "0px" }}>
  821.       {/* Vertical Line (connects this item to parent, but stops at the last child) */}
  822.       {level > 0 && hasSiblingsAbove && (
  823.         <div
  824.           style={{
  825.             position: "absolute",
  826.             left: "-10px",
  827.             top: "0",
  828.             bottom: "0",
  829.             width: "2px",
  830.             backgroundColor: "gray"
  831.           }}
  832.         ></div>
  833.       )}
  834.  
  835.       {/* Horizontal Connector (connects parent to its children) */}
  836.       {level > 0 && (
  837.         <div
  838.           style={{
  839.             position: "absolute",
  840.             left: "-10px",
  841.             top: "12px",
  842.             width: "10px",
  843.             height: "2px",
  844.             backgroundColor: "gray"
  845.           }}
  846.         ></div>
  847.       )}
  848.  
  849.       {/* Directory/File Name */}
  850.       <div className="directory-item" onClick={handleToggle} style={{ cursor: isFolder ? "pointer" : "default", display: "flex", alignItems: "center" }}>
  851.         {isFolder ? (expanded ? "\u{1F4C2}" : "\u{1F4C1}") : "\u{1F4C4}"} {data.name}
  852.       </div>
  853.  
  854.       {/* Render Children */}
  855.       {expanded && isFolder && (
  856.         <div style={{ marginLeft: "15px", paddingLeft: "10px", position: "relative" }}>
  857.           {data.children.map((child, index) => (
  858.             <Directory
  859.               key={index}
  860.               data={child}
  861.               isLast={index === data.children.length - 1}
  862.               level={level + 1}
  863.               hasSiblingsAbove={true} // Ensure the vertical line appears properly
  864.             />
  865.           ))}
  866.  
  867.           {/* STOP the vertical line at the last child */}
  868.           {isLast && (
  869.             <div
  870.               style={{
  871.                 position: "absolute",
  872.                 left: "-10px",
  873.                 top: "0",
  874.                 bottom: "12px", // Stops the line exactly at the bottom of the last child
  875.                 width: "2px",
  876.                 backgroundColor: "gray"
  877.               }}
  878.             ></div>
  879.           )}
  880.         </div>
  881.       )}
  882.     </div>
  883.   );
  884. };
  885.  
  886. // Main App Component
  887. const App = () => {
  888.   return (
  889.     <div style={{ padding: "20px", fontFamily: "Arial, sans-serif" }}>
  890.       <h2>{`${"\u{1F4C1}"} File Explorer`}</h2>
  891.       <Directory data={directoryData} />
  892.     </div>
  893.   );
  894. };
  895.  
  896. export default App;
  897.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement