summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/package-lock.json42
-rw-r--r--client/package.json1
-rw-r--r--client/src/App.js102
-rw-r--r--client/src/Influencers.css22
-rw-r--r--client/src/Influencers.js102
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;