-
Notifications
You must be signed in to change notification settings - Fork 29
fetch tabs data and cache it #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
AturiheihiBlendon
wants to merge
1
commit into
Mereb-Tech:main
Choose a base branch
from
AturiheihiBlendon:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,32 +1,84 @@ | ||
| * { | ||
| margin: 0; | ||
| padding: 0; | ||
| box-sizing: border-box; | ||
| margin: 0; | ||
| padding: 0; | ||
| box-sizing: border-box; | ||
| } | ||
|
|
||
| body { | ||
| background-color: black; | ||
| font-family: 'Roboto', sans-serif; | ||
| margin: 20px; | ||
| background-color: black; | ||
| font-family: "Roboto", sans-serif; | ||
| margin: 20px; | ||
| } | ||
|
|
||
| .container { | ||
| width: 960px; | ||
| margin: 0 auto; | ||
| width: 960px; | ||
| margin: 0 auto; | ||
| } | ||
| /* TODO: Add css here */ | ||
| .tabs { | ||
| display: flex; | ||
| background-color: #333; | ||
| } | ||
|
|
||
| .tab-button { | ||
| flex: 1; | ||
| padding: 10px 20px; | ||
| border: none; | ||
| cursor: pointer; | ||
| background-color: #333; | ||
| color: #fff; | ||
| height: 50px; | ||
| } | ||
|
|
||
| .tab-button.active { | ||
| background-color: #114277; | ||
| } | ||
|
|
||
| @media only screen and (max-width: 960px) { | ||
| .tab-button:hover { | ||
| background-color: #555; | ||
| } | ||
|
|
||
| .tab-content { | ||
| padding: 0; | ||
| margin: 0; | ||
| background-color: white; | ||
| } | ||
|
|
||
| .tab-content div { | ||
| padding: 20px; | ||
| background-color: white; | ||
| } | ||
|
|
||
| .container { | ||
| width: 100%; | ||
| } | ||
| .title { | ||
| padding-top: 20px; | ||
| padding-left: 20px; | ||
| font-size: 1.5rem; | ||
| } | ||
|
|
||
| .text { | ||
| font-size: 1rem; | ||
| line-height: 1.5; | ||
| } | ||
| .error { | ||
| color: red; | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| height: 200px; | ||
| } | ||
| .loading { | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| height: 200px; | ||
| } | ||
|
|
||
| @media only screen and (max-width: 960px) { | ||
| .container { | ||
| width: 100%; | ||
| } | ||
|
|
||
| .content { | ||
| padding: 50px; | ||
| } | ||
| } | ||
| .content { | ||
| padding: 50px; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,39 +1,99 @@ | ||
| import React from 'react'; | ||
| import React, { useState, useReducer, useEffect } from "react"; | ||
|
|
||
| const initialState = { | ||
| data: {}, | ||
| error: null, | ||
| }; | ||
|
|
||
| const reducer = (state, action) => { | ||
| switch (action.type) { | ||
| case "FETCH_SUCCESS": | ||
| return { | ||
| ...state, | ||
| data: { | ||
| ...state.data, | ||
| [action.tabIndex]: action.data, | ||
| }, | ||
| error: null, | ||
| }; | ||
| case "FETCH_ERROR": | ||
| return { | ||
| ...state, | ||
| error: action.error, | ||
| }; | ||
| default: | ||
| return state; | ||
| } | ||
| }; | ||
|
|
||
| const Tabs = () => { | ||
| const [activeTab, setActiveTab] = useState(0); | ||
| const [state, dispatch] = useReducer(reducer, initialState); | ||
|
|
||
| // Fetch tab content | ||
| const fetchTabContent = async (tabIndex) => { | ||
| // check if data for active tab is already cached and skip fetching if its already cached | ||
| if (state.data[tabIndex]) { | ||
| console.log("Using cached data:", state.data[tabIndex]); | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| const response = await fetch( | ||
| "https://thingproxy.freeboard.io/fetch/https://loripsum.net/api/" | ||
| ); | ||
| if (!response.ok) { | ||
| throw new Error("Network response was not ok"); | ||
| } | ||
| const data = await response.text(); | ||
| // console.log("Fetched data:", data); | ||
| dispatch({ type: "FETCH_SUCCESS", tabIndex, data }); | ||
| } catch (error) { | ||
| console.error("Error fetching data:", error); | ||
| dispatch({ type: "FETCH_ERROR", tabIndex, error: "Error fetching data" }); | ||
| } | ||
| }; | ||
|
|
||
| // const tabs = [ | ||
| // { | ||
| // id: 1, | ||
| // tabTitle: 'Tab 1', | ||
| // title: 'Title 1', | ||
| // content: 'In sint do non adipisicing incididunt excepteur sit. Voluptate esse aliqua pariatur dolor ex occaecat sunt eu. Pariatur ullamco id dolore sint proident sint nostrud nisi sit id est. Duis et excepteur cupidatat sint nisi dolore qui irure qui in id excepteur irure laboris. Pariatur mollit duis cupidatat nisi Lorem non et in dolor aliquip ea sint aute. Dolore aute duis laboris exercitation occaecat sunt. Enim veniam Lorem do ipsum aliqua qui eu ipsum consectetur ex dolore ea ipsum.' | ||
| // }, | ||
| // { | ||
| // id: 2, | ||
| // tabTitle: 'Tab 2', | ||
| // title: 'Title 2', | ||
| // content: 'Non aliquip fugiat velit ad officia Lorem tempor cillum incididunt elit proident mollit. Reprehenderit qui nisi ut occaecat minim velit deserunt occaecat quis magna mollit. Veniam proident consectetur sunt mollit est magna Lorem voluptate enim cupidatat consequat. Et pariatur aliquip commodo nisi deserunt exercitation enim officia voluptate in nisi. Eu ea esse qui est ea pariatur nostrud non elit irure. Ad exercitation Lorem exercitation ipsum eiusmod ea duis ad mollit veniam aliquip veniam. Lorem pariatur elit ea duis.' | ||
| // }, | ||
| // { | ||
| // id: 3, | ||
| // tabTitle: 'Tab 3', | ||
| // title: 'Title 3', | ||
| // content: 'Deserunt et elit elit ad dolor magna. Nisi amet consectetur Lorem eiusmod dolore adipisicing do reprehenderit. Voluptate consequat magna nostrud in officia labore. Minim excepteur consectetur quis nostrud nisi magna duis sunt sint qui. Fugiat ea reprehenderit eiusmod proident officia. Consequat labore qui velit Lorem consectetur incididunt ut nisi.' | ||
| // }, | ||
| // { | ||
| // id: 4, | ||
| // tabTitle: 'Tab 4', | ||
| // title: 'Title 4', | ||
| // content: 'Minim in dolor do fugiat laborum duis labore consectetur. Amet ut sint ipsum dolor ad nostrud commodo sunt veniam enim aliquip nulla sint ullamco. Do cupidatat et quis laborum esse est commodo. Commodo sunt consectetur do consequat minim occaecat id magna ullamco consequat irure.' | ||
| // } | ||
| // ]; | ||
|
|
||
| return ( | ||
| <div className='container'> | ||
| {/* TODO Add tabs here */} | ||
| // fetch data whenever active tab changes | ||
| useEffect(() => { | ||
| fetchTabContent(activeTab); | ||
| }, [activeTab]); | ||
|
|
||
| const tabs = ["Tab 1", "Tab 2", "Tab 3", "Tab 4"]; | ||
|
|
||
| return ( | ||
| <div className="container"> | ||
| {/* TODO Add tabs here */} | ||
| <div className="container"> | ||
| <div className="tabs"> | ||
| {tabs.map((tab, index) => ( | ||
| <button | ||
| key={index} | ||
| onClick={() => setActiveTab(index)} | ||
| className={`tab-button ${activeTab === index ? "active" : ""}`} | ||
| > | ||
| {tab} | ||
| </button> | ||
| ))} | ||
| </div> | ||
| <div className="tab-content"> | ||
| {state.error ? ( | ||
| <p className="error">{state.error}</p> | ||
| ) : state.data[activeTab] ? ( | ||
| <> | ||
| <h2 className="title">Title {activeTab + 1}</h2> | ||
| <div | ||
| className="text" | ||
| dangerouslySetInnerHTML={{ __html: state.data[activeTab] }} | ||
| /> | ||
| </> | ||
| ) : ( | ||
| <p className="loading">Loading content...</p> | ||
| )} | ||
| </div> | ||
| ); | ||
| } | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default Tabs; | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid using
dangerouslySetInnerHTMLto prevent XSS vulnerabilitiesUsing
dangerouslySetInnerHTMLcan expose users to cross-site scripting (XSS) attacks if the content is not properly sanitized. Consider sanitizing the content before rendering, or using a library likeDOMPurifyto sanitize the HTML.Apply this diff to address the issue:
🧰 Tools
🪛 Biome
[error] 87-87: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)