diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/package-lock.json | 42 | ||||
-rw-r--r-- | client/package.json | 1 | ||||
-rw-r--r-- | client/src/App.js | 102 | ||||
-rw-r--r-- | client/src/Influencers.css | 22 | ||||
-rw-r--r-- | client/src/Influencers.js | 102 |
5 files changed, 242 insertions, 27 deletions
diff --git a/client/package-lock.json b/client/package-lock.json index a6aacf5..a6fa0c1 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -14,6 +14,7 @@ "axios": "^1.7.2", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-router-dom": "^6.24.0", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" } @@ -3562,6 +3563,15 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.0.tgz", + "integrity": "sha512-2D6XaHEVvkCn682XBnipbJjgZUU7xjLtA4dGJRBVUKpEaDYOZMENZoZjAOSb7qirxt5RupjzZxz4fK2FO+EFPw==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -16288,6 +16298,38 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.24.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.24.0.tgz", + "integrity": "sha512-sQrgJ5bXk7vbcC4BxQxeNa5UmboFm35we1AFK0VvQaz9g0LzxEIuLOhHIoZ8rnu9BO21ishGeL9no1WB76W/eg==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.17.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.24.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.24.0.tgz", + "integrity": "sha512-960sKuau6/yEwS8e+NVEidYQb1hNjAYM327gjEyXlc6r3Skf2vtwuJ2l7lssdegD2YjoKG5l8MsVyeTDlVeY8g==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.17.0", + "react-router": "6.24.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", diff --git a/client/package.json b/client/package.json index b660797..70e70ca 100644 --- a/client/package.json +++ b/client/package.json @@ -9,6 +9,7 @@ "axios": "^1.7.2", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-router-dom": "^6.24.0", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" }, diff --git a/client/src/App.js b/client/src/App.js index eaeca2c..2d19281 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -1,9 +1,13 @@ import React, { useEffect, useState } from 'react'; +import { BrowserRouter as Router, Route, Link, Routes } from 'react-router-dom'; import axios from 'axios'; import './App.css'; +import Influencers from './Influencers'; function App() { const [downloadedFiles, setDownloadedFiles] = useState([]); + const [isAuthenticated, setIsAuthenticated] = useState(false); + const [adminPassword, setAdminPassword] = useState(''); useEffect(() => { fetchDownloadedFiles(); @@ -22,35 +26,79 @@ function App() { } }; + const handleLogin = (password) => { + setAdminPassword(password); + setIsAuthenticated(true); + }; + return ( - <div className="App"> - <header className="App-header"> - <h1 className="App-title">Insta Local</h1> - <div className="downloaded-content"> - {downloadedFiles.length === 0 ? ( - <p>No content available</p> - ) : ( - downloadedFiles.map((file, index) => { - const fileUrl = `http://localhost:5001/static/${file}`; - console.log('Fetching file:', fileUrl); // Log the file URL - return ( - <div key={index} className="file-item"> - {file.endsWith('.mp4') ? ( - <video controls> - <source src={fileUrl} type="video/mp4" /> - Your browser does not support the video tag. - </video> - ) : ( - <img src={fileUrl} alt={file} /> - )} - </div> - ); - }) - )} - </div> - </header> - </div> + <Router> + <div className="App"> + <header className="App-header"> + <h1 className="App-title">Insta Local</h1> + <nav> + <Link to="/">Home</Link> + <Link to="/influencers">Add Influencers</Link> + </nav> + </header> + <Routes> + <Route path="/" element={ + <div className="downloaded-content"> + {downloadedFiles.length === 0 ? ( + <p>No content available</p> + ) : ( + downloadedFiles.map((file, index) => { + const fileUrl = `http://localhost:5001/static/${file}`; + return ( + <div key={index} className="file-item"> + {file.endsWith('.mp4') ? ( + <video controls> + <source src={fileUrl} type="video/mp4" /> + Your browser does not support the video tag. + </video> + ) : ( + <img src={fileUrl} alt={file} /> + )} + </div> + ); + }) + )} + </div> + } /> + <Route path="/influencers" element={ + isAuthenticated ? ( + <Influencers adminPassword={adminPassword} /> + ) : ( + <Login onLogin={handleLogin} /> + ) + } /> + </Routes> + </div> + </Router> ); } +const Login = ({ onLogin }) => { + const [password, setPassword] = useState(''); + + const handleSubmit = (event) => { + event.preventDefault(); + onLogin(password); + }; + + return ( + <form onSubmit={handleSubmit}> + <label> + Password: + <input + type="password" + value={password} + onChange={(e) => setPassword(e.target.value)} + /> + </label> + <button type="submit">Login</button> + </form> + ); +}; + export default App; diff --git a/client/src/Influencers.css b/client/src/Influencers.css new file mode 100644 index 0000000..443762e --- /dev/null +++ b/client/src/Influencers.css @@ -0,0 +1,22 @@ +.influencers { + padding: 20px; +} + +.password-input, .add-profile, .export-import { + margin-bottom: 20px; +} + +.profile-list ul { + list-style-type: none; + padding: 0; +} + +.profile-list li { + display: flex; + justify-content: space-between; + margin-bottom: 10px; +} + +button { + margin-left: 10px; +} diff --git a/client/src/Influencers.js b/client/src/Influencers.js new file mode 100644 index 0000000..a72d654 --- /dev/null +++ b/client/src/Influencers.js @@ -0,0 +1,102 @@ +import React, { useState, useEffect, useCallback } from 'react'; +import axios from 'axios'; + +function Influencers({ adminPassword }) { + const [profiles, setProfiles] = useState([]); + const [newProfile, setNewProfile] = useState(''); + + const fetchProfiles = useCallback(async () => { + try { + const response = await axios.get('http://localhost:5001/profiles', { + headers: { Authorization: `Bearer ${adminPassword}` } + }); + console.log('Fetched profiles:', response.data); + setProfiles(response.data); + } catch (error) { + console.error('Error fetching profiles:', error); + } + }, [adminPassword]); + + useEffect(() => { + fetchProfiles(); + }, [fetchProfiles]); + + const addProfile = async () => { + try { + await axios.post( + 'http://localhost:5001/profiles', + { username: newProfile }, + { headers: { Authorization: `Bearer ${adminPassword}` } } + ); + setNewProfile(''); + fetchProfiles(); + } catch (error) { + console.error('Error adding profile:', error); + } + }; + + const handleJsonUpload = async (event) => { + const file = event.target.files[0]; + if (file) { + const formData = new FormData(); + formData.append('file', file); + + try { + await axios.post('http://localhost:5001/upload', formData, { + headers: { + 'Content-Type': 'multipart/form-data', + Authorization: `Bearer ${adminPassword}` + } + }); + fetchProfiles(); + } catch (error) { + console.error('Error uploading JSON file:', error); + } + } + }; + + const exportJson = async () => { + try { + const response = await axios.get('http://localhost:5001/export', { + headers: { Authorization: `Bearer ${adminPassword}` }, + responseType: 'blob' + }); + const url = window.URL.createObjectURL(new Blob([response.data])); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', 'influencers.json'); + document.body.appendChild(link); + link.click(); + } catch (error) { + console.error('Error exporting JSON file:', error); + } + }; + + return ( + <div> + <h2>Add Influencers</h2> + <input + type="text" + value={newProfile} + onChange={(e) => setNewProfile(e.target.value)} + placeholder="Enter Instagram username" + /> + <button onClick={addProfile}>Add</button> + <h3>Current Influencers</h3> + <ul> + {profiles.map((profile, index) => ( + <li key={index}>{profile}</li> + ))} + </ul> + <h3>Import/Export Influencers</h3> + <input + type="file" + accept="application/json" + onChange={handleJsonUpload} + /> + <button onClick={exportJson}>Export JSON</button> + </div> + ); +} + +export default Influencers; |