├── .gitignore
├── README.md
├── images
├── Web
│ ├── tag1.png
│ └── tag2.png
└── desktop-preview.jpg
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
└── robots.txt
├── src
├── App.ts
├── api
│ └── api.ts
├── assets
│ ├── icon-down.svg
│ ├── icon-facebook.svg
│ ├── icon-instagram.svg
│ ├── icon-twitter.svg
│ ├── icon-up.svg
│ └── icon-youtube.svg
├── components
│ ├── FollowersCard
│ │ ├── index.ts
│ │ └── styles.scss
│ ├── Header
│ │ ├── index.ts
│ │ └── styles.scss
│ ├── OverviewCard
│ │ ├── index.ts
│ │ └── styles.scss
│ └── ToggleButton
│ │ ├── index.ts
│ │ └── styles.scss
├── contexts
│ └── themeContext.ts
├── hooks
│ ├── useLocalStorage.ts
│ └── useTheme.ts
├── index.ts
├── pages
│ └── Dashboard
│ │ ├── index.ts
│ │ └── styles.scss
├── routes
│ └── index.ts
└── styles
│ ├── app.scss
│ └── global.scss
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Social Media Dashboard App
2 |
3 | 
4 |
5 | Welcome to the Social Media Dashboard App! This application allows you to manage and monitor your social media accounts from a single centralized dashboard. Whether you're a social media manager, influencer, or someone who wants to stay on top of their social media presence, this app provides a convenient way to streamline your activities.
6 |
7 | ## Features
8 |
9 | 1. **Account Integration**: Connect your social media accounts, such as Facebook, Twitter, Instagram, LinkedIn, and more, to the app.
10 | 2. **Unified Dashboard**: Access all your connected accounts from a single dashboard, eliminating the need to switch between multiple apps or tabs.
11 | 3. **Real-time Analytics**: Get real-time insights into your social media performance, including followers, likes, comments, and engagement metrics.
12 | 4. **Scheduling and Publishing**: Schedule and publish posts across multiple social media platforms at once, saving time and effort.
13 | 5. **Social Listening**: Monitor mentions, hashtags, and keywords relevant to your brand or industry to stay updated on trends and engage with your audience effectively.
14 | 6. **Inbox Management**: Receive and respond to direct messages, comments, and notifications from different social media platforms within the app.
15 | 7. **Content Curation**: Discover and curate content from various sources, such as articles, images, and videos, to share with your audience.
16 | 8. **Collaboration and Team Management**: Collaborate with team members and assign roles and permissions for efficient social media management.
17 | 9. **Customizable Reports**: Generate customized reports with key performance indicators (KPIs) and export them for analysis or sharing with stakeholders.
18 |
19 | ## Installation
20 |
21 | To install and run the Social Media Dashboard App, follow these steps:
22 |
23 | 1. Clone the repository to your local machine:
24 |
25 | ```
26 | git clone https://github.com/MithuLix/Social-Media-Dashboard.git
27 | ```
28 |
29 | 2. Navigate to the project directory:
30 |
31 | ```
32 | cd social-media-dashboard
33 | ```
34 |
35 | 3. Install the dependencies using a package manager like npm or yarn:
36 |
37 | ```
38 | npm install
39 | ```
40 |
41 | 4. Configure the necessary API keys and credentials for each social media platform in the app's configuration file. Refer to the documentation for each platform to obtain the required credentials.
42 |
43 | 5. Build and start the app:
44 |
45 | ```
46 | npm start
47 | ```
48 |
49 | 6. Open your web browser and visit `http://localhost:3000` to access the Social Media Dashboard App.
50 |
51 | ## Usage
52 |
53 | Once you have installed and launched the app, follow these steps to get started:
54 |
55 | 1. Create an account or log in to your existing account.
56 |
57 | 2. Connect your desired social media accounts using the provided integration options.
58 |
59 | 3. Explore the dashboard to view real-time analytics, scheduled posts, and incoming messages.
60 |
61 | 4. Use the scheduling and publishing features to plan and publish content across your social media accounts.
62 |
63 | 5. Monitor your brand or industry-related keywords and engage with your audience using the social listening features.
64 |
65 | 6. Customize the app's settings and notifications according to your preferences.
66 |
67 | 7. Generate and export reports to track your social media performance and share insights with others.
68 |
69 | ## Technologies
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | ## Contributing
78 |
79 | We welcome contributions to the Social Media Dashboard App! If you have any suggestions, bug reports, or feature requests, please open an issue on the project repository.
80 |
81 | If you would like to contribute code to the project, follow these steps:
82 |
83 | 1. Fork the repository on GitHub.
84 |
85 | 2. Create a new branch for your feature or bug fix:
86 |
87 | ```
88 | git checkout -b feature/your-feature-name
89 | ```
90 |
91 | 3. Make the necessary changes and commit them:
92 |
93 | ```
94 | git commit -m "Add your commit message"
95 | ```
96 |
97 | 4. Push your branch to your forked repository:
98 |
99 | ```
100 | git push origin feature/your-feature-name
101 | ```
102 |
103 |
104 |
105 |
106 | MIT License
107 |
108 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
109 |
110 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
111 |
112 | THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
113 |
--------------------------------------------------------------------------------
/images/Web/tag1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mithulix/Social-Media-Dashboard/e8a54e30c0eb3202f07b47abf0257f1ba7cc75a5/images/Web/tag1.png
--------------------------------------------------------------------------------
/images/Web/tag2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mithulix/Social-Media-Dashboard/e8a54e30c0eb3202f07b47abf0257f1ba7cc75a5/images/Web/tag2.png
--------------------------------------------------------------------------------
/images/desktop-preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mithulix/Social-Media-Dashboard/e8a54e30c0eb3202f07b47abf0257f1ba7cc75a5/images/desktop-preview.jpg
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "social-media-dashboard",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.16.5",
7 | "@testing-library/react": "^13.4.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "axios": "^1.4.0",
10 | "react": "^18.2.0",
11 | "react-dom": "^18.2.0",
12 | "react-scripts": "^2.1.3",
13 | "saas": "^1.0.0",
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 | "devDependencies": {
41 | "typescript": "^5.0.4"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mithulix/Social-Media-Dashboard/e8a54e30c0eb3202f07b47abf0257f1ba7cc75a5/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.ts:
--------------------------------------------------------------------------------
1 | // Import the useTheme hook from the hooks folder
2 | import useTheme from './hooks/useTheme';
3 | // Import the Router component from the routes folder
4 | import { Router } from './routes';
5 |
6 | // Import the SCSS stylesheets for the app
7 | import './styles/app.scss';
8 | import './styles/global.scss';
9 |
10 | // Define the App component
11 | function App() {
12 | // Call the useTheme hook to retrieve the current theme
13 | const { theme } = useTheme();
14 |
15 | // Return the app's JSX
16 | return (
17 |
18 |
19 |
20 |
21 | );
22 | }
23 |
24 | // Export the App component as the default export of this module
25 | export default App;
26 |
--------------------------------------------------------------------------------
/src/api/api.ts:
--------------------------------------------------------------------------------
1 | // Importing axios package to make HTTP requests
2 | import axios from "axios";
3 |
4 | // Defining the base URL for the JSON server API
5 | const urlServer = "https://my-json-server.typicode.com/Cunegundess/serverTeste";
6 |
7 | // Defining the dataFake type that represents the structure of the data returned from the "/dataFake" endpoint of the server
8 | export type dataFake = {
9 | readonly id: string; // a required string field that contains the unique identifier of the data
10 | nickname: string; // a string field that contains the nickname of the data
11 | followers: number; // a number field that contains the number of followers of the data
12 | followersOverview: number; // a number field that contains the overview of followers of the data
13 | readonly type: string; // a required string field that contains the type of the data
14 | status: boolean; // a boolean field that indicates the status of the data
15 | };
16 |
17 | // Defining the fakeOverviewData type that represents the structure of the data returned from the "/fakeOverview" endpoint of the server
18 | export type fakeOverviewData = {
19 | readonly id: string; // a required string field that contains the unique identifier of the data
20 | title: string; // a string field that contains the title of the data
21 | total: number; // a number field that contains the total of the data
22 | percent: number; // a number field that contains the percentage of the data
23 | readonly type: string; // a required string field that contains the type of the data
24 | status: boolean; // a boolean field that indicates the status of the data
25 | };
26 |
27 | // Defining the fetchData function that makes an HTTP GET request to the provided URL and returns the response data
28 | export async function fetchData(url: string): Promise {
29 | try {
30 | const response = await axios.get(url); // Making an HTTP GET request using axios package
31 | return response.data; // Returning the response data
32 | } catch (error) {
33 | console.error(error); // Logging the error to the console
34 | return []; // Returning an empty array in case of error
35 | }
36 | }
37 |
38 | // Defining the getDataFake function that returns an array of dataFake objects obtained from the server
39 | export async function getDataFake(): Promise {
40 | const dataUrl = `${urlServer}/dataFake`; // Constructing the URL for the "/dataFake" endpoint
41 | return await fetchData(dataUrl); // Making an HTTP GET request to the "/dataFake" endpoint and returning the response data as an array of dataFake objects
42 | }
43 |
44 | // Defining the getFakeOverviewData function that returns an array of fakeOverviewData objects obtained from the server
45 | export async function getFakeOverviewData(): Promise {
46 | const overviewUrl = `${urlServer}/fakeOverview`; // Constructing the URL for the "/fakeOverview" endpoint
47 | return await fetchData(overviewUrl); // Making an HTTP GET request to the "/fakeOverview" endpoint and returning the response data as an array of fakeOverviewData objects
48 | }
49 |
--------------------------------------------------------------------------------
/src/assets/icon-down.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icon-facebook.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icon-instagram.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icon-twitter.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icon-up.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icon-youtube.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/FollowersCard/index.ts:
--------------------------------------------------------------------------------
1 | // Import the necessary SVG icons and the useState hook from React
2 | import { dataFake } from "../../api/api";
3 | import { ReactComponent as DownSvg } from "../../assets/icon-down.svg";
4 | import { ReactComponent as UpSvg } from "../../assets/icon-up.svg";
5 | import { ReactComponent as FacebookSvg } from "../../assets/icon-facebook.svg";
6 | import { ReactComponent as InstagramSvg } from "../../assets/icon-instagram.svg";
7 | import { ReactComponent as TwitterSvg } from "../../assets/icon-twitter.svg";
8 | import { ReactComponent as YoutubeSvg } from "../../assets/icon-youtube.svg";
9 | import { useState } from 'react'
10 |
11 | // Import the styles for this component
12 | import "./styles.scss";
13 |
14 | // Define the shape of the props that this component accepts
15 | type Props = {
16 | borderTheme?: string;
17 | data: dataFake;
18 | };
19 |
20 | // This function takes a string representing a social media platform
21 | // and returns the corresponding SVG icon for that platform
22 | function iconSvg(type: string) {
23 | switch (type) {
24 | case "instagram":
25 | return ;
26 | case "facebook":
27 | return ;
28 | case "youtube":
29 | return ;
30 | default:
31 | return ;
32 | }
33 | }
34 |
35 | // This function takes a fake data object and returns a new object with
36 | // randomly generated numbers for the followers count, followers overview,
37 | // and status (whether the count has gone up or down)
38 | function calculateNumbers(numbers: dataFake) {
39 | const followers = Math.floor(Math.random() * 100000) + 1000;
40 | const followersOverview = Math.floor(Math.random() * 1000) + 1000;
41 | const status = Math.random() < 0.5;
42 |
43 | return {
44 | followers,
45 | followersOverview,
46 | status
47 | };
48 | }
49 |
50 | // This is the main component that renders the followers card
51 | export function FollowersCard({ borderTheme, data }: Props) {
52 | // Initialize the state with a null value
53 | const [latestNumbers] = useState(null);
54 |
55 | // If no data is provided, return null
56 | if (!data) {
57 | return null;
58 | }
59 |
60 | // Calculate the random numbers to be displayed on the card
61 | const dashboardNumbers = calculateNumbers(latestNumbers || data);
62 |
63 | return (
64 | // Render the followers card using the provided data and generated numbers
65 |
66 |
67 |
68 |
69 | {/* Render the SVG icon for the social media platform */}
70 | {iconSvg(data.type)}
71 | {/* Render the nickname of the platform */}
72 | {data.nickname}
73 |
74 |
75 |
76 | {/* Render the followers count */}
77 |
78 | {dashboardNumbers.followers}
79 |
80 | {/* Render "subscribers" if the platform is YouTube, "followers" otherwise */}
81 | {data.type === "youtube" ? "subscribers" : "followers"}
82 |
11 | { // Using a ternary operator to render different JSX based on the current theme
12 | theme === "dark-mode" ? // if the current theme is "dark-mode"
13 | // render an input element with the "checked" attribute set to true
14 | :
15 | // otherwise, render an input element with the "checked" attribute set to false
16 | }
17 |
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/ToggleButton/styles.scss:
--------------------------------------------------------------------------------
1 | :root {
2 | /** sunny side **/
3 | --blue-background: #c2e9f6;
4 | --blue-border: #72cce3;
5 | --blue-color: #96dcee;
6 | --yellow-background: #fffaa8;
7 | --yellow-border: #f5eb71;
8 | /** dark side **/
9 | --indigo-background: #221b41;
10 | --indigo-border: #47396d;
11 | --indigo-color: #6b7abb;
12 | --gray-border: rgb(177, 177, 177);
13 | --gray-dots: #ebe5e6;
14 | }
15 |
16 | @keyframes reverse {
17 | 0% {
18 | left: 25px;
19 | width: 20px;
20 | }
21 | 60% {
22 | left: 3px;
23 | width: 40px;
24 | }
25 | 100% {
26 | left: 3px;
27 | }
28 | }
29 |
30 | @keyframes switch {
31 | 0% {
32 | left: 3px;
33 | }
34 | 60% {
35 | left: 3px;
36 | width: 40px;
37 | }
38 | 100% {
39 | left: 25px;
40 | width: 20px;
41 | }
42 | }
43 |
44 | .toggle-content {
45 | .toggle-checkbox {
46 | display: none;
47 | }
48 |
49 | /* background */
50 | .toggle-label {
51 | width: 3rem;
52 | height: 1.5rem;
53 | background: var(--toggle);
54 | border-radius: 0.75rem;
55 | display: flex;
56 | position: relative;
57 | transition: all 350ms ease-in;
58 | }
59 |
60 | .toggle-checkbox:checked + .toggle-label {
61 | background: var(--toggle-gradient);
62 | }
63 |
64 | .toggle-checkbox:checked + .toggle-label:before {
65 | animation-name: reverse;
66 | animation-duration: 350ms;
67 | animation-fill-mode: forwards;
68 | transition: all 360ms ease-in;
69 | background: var(--card-accent);
70 | }
71 |
72 | .toggle-label:before {
73 | animation-name: switch;
74 | animation-duration: 350ms;
75 | animation-fill-mode: forwards;
76 | content: "";
77 | width: 1.2rem;
78 | height: 1.2rem;
79 | top: 0.13rem;
80 | position: absolute;
81 | border-radius: 1.2rem;
82 | background: var(--card);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/contexts/themeContext.ts:
--------------------------------------------------------------------------------
1 | import { createContext, ReactNode } from 'react'; // Import necessary dependencies
2 | import { useLocalStorage } from '../hooks/useLocalStorage'; // Import custom hook for handling local storage
3 |
4 | type ThemeContextData = {
5 | theme: string;
6 | themeToggle: () => void;
7 | }
8 |
9 | // Create a new context with the default value being an empty object
10 | export const ThemeContext = createContext({} as ThemeContextData);
11 |
12 | type ThemeContextProviderProps = {
13 | children: ReactNode;
14 | }
15 |
16 | // Create a new component to provide the theme context
17 | export function ThemeContextProvider({ children }: ThemeContextProviderProps) {
18 | // Use the custom hook to get and set the theme in local storage
19 | const [theme, setTheme] = useLocalStorage('theme', 'dark-mode');
20 |
21 | // Create a function to toggle the theme
22 | function themeToggle() {
23 | if (theme === 'dark-mode') {
24 | setTheme('light-mode');
25 | } else {
26 | setTheme('dark-mode');
27 | }
28 | }
29 |
30 | // Render the context provider and pass in the current theme and the toggle function as context value
31 | return (
32 |
35 | {children}
36 |
37 | )
38 | }
39 |
--------------------------------------------------------------------------------
/src/hooks/useLocalStorage.ts:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | // Custom hook that allows you to store data in local storage
4 | export function useLocalStorage(key: string, initialValue: string) {
5 |
6 | // Use the useState hook to define a state variable that holds the current value of the item
7 | const [storedValue, setStoredValue] = useState(() => {
8 | try {
9 | // Get the value from local storage using the specified key
10 | const item = window.localStorage.getItem(key);
11 | // If the item exists, parse it from JSON and return it. Otherwise, return the initial value passed to the hook
12 | return item ? JSON.parse(item) : initialValue;
13 | } catch (error) {
14 | // If there's an error, log it and return the initial value
15 | console.log(error);
16 | return initialValue;
17 | }
18 | });
19 |
20 | // Define a function to update the value stored in local storage
21 | const setValue = (value: any) => {
22 | try {
23 | // If the new value is a function, call it with the current value of the item to get the new value
24 | const valueToStore =
25 | value instanceof Function ? value(storedValue) : value;
26 | // Update the state variable with the new value
27 | setStoredValue(valueToStore);
28 | // Store the new value in local storage using the specified key
29 | window.localStorage.setItem(key, JSON.stringify(valueToStore));
30 | } catch (error) {
31 | // If there's an error, log it
32 | console.log(error);
33 | }
34 | };
35 |
36 | // Return an array containing the current value of the item and the function to update it
37 | return [storedValue, setValue];
38 | }
39 |
--------------------------------------------------------------------------------
/src/hooks/useTheme.ts:
--------------------------------------------------------------------------------
1 | import { useContext } from 'react';
2 | import { ThemeContext } from '../contexts/themeContext';
3 |
4 | // This custom hook provides access to the theme and themeToggle function
5 | const useTheme = () => {
6 | // Use the useContext hook to get the current ThemeContext
7 | const context = useContext(ThemeContext);
8 |
9 | // If the context is undefined (i.e. it hasn't been provided by a parent component),
10 | // throw an error
11 | if (!context) {
12 | throw new Error('Nenhum contexto encontrado');
13 | }
14 |
15 | // Otherwise, return the context object (which includes the theme and themeToggle function)
16 | return context;
17 | }
18 |
19 | // Export the custom hook as the default export of this module
20 | export default useTheme;
21 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | import App from './App';
5 | import { ThemeContextProvider } from './contexts/themeContext';
6 |
7 | ReactDOM.render(
8 |
9 |
10 |
11 |
12 | ,
13 | document.getElementById('root')
14 | );
15 |
--------------------------------------------------------------------------------
/src/pages/Dashboard/index.ts:
--------------------------------------------------------------------------------
1 | import { FollowersCard } from "../../components/FollowersCard";
2 | import { Header } from "../../components/Header";
3 | import { OverviewCard } from "../../components/OverviewCard";
4 | import { useEffect, useState } from "react";
5 | import { getDataFake, getFakeOverviewData } from "../../api/api";
6 | import { dataFake, fakeOverviewData } from "../../api/api";
7 | import "./styles.scss";
8 |
9 | export function Dashboard() {
10 | const [data, setData] = useState([]); // State for followers data
11 | const [dataOverview, setDataOverview] = useState([]); // State for overview data
12 |
13 | useEffect(() => {
14 | async function fetchData() {
15 | const fetchedData = await getDataFake(); // Fetch followers data
16 | const fetchedDataOverview = await getFakeOverviewData(); // Fetch overview data
17 | setData(fetchedData);
18 | setDataOverview(fetchedDataOverview);
19 | }
20 | fetchData();
21 |
22 | // Set up an interval to refetch data every 5 seconds
23 | const interval = setInterval(() => {
24 | fetchData();
25 | }, 5000);
26 |
27 | // Clean up the interval when the component unmounts
28 | return () => clearInterval(interval);
29 | }, []);
30 |
31 | return (
32 |
33 | {/* Render the header component, passing the first follower data as props */}
34 |
35 |
36 |
37 | {data.map((item) => (
38 | // Render the FollowersCard component for each follower data, passing it as props along with the follower's border theme and ID
39 | ))}
40 |
41 |
42 |
Overview - Today
43 |
44 |
45 | {dataOverview.map((item) => (
46 | // Render the OverviewCard component for each overview data, passing it as props along with the ID
47 | ))}
48 |