App.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
import React, { useState, useEffect } from "react"; import { GoogleLogin } from "react-google-login"; import { Button, Form, FormControl } from "react-bootstrap"; import "bootstrap/dist/css/bootstrap.min.css"; import { gapi } from "gapi-script"; const API_KEY = ""; // Your API key const CLIENT_ID = ""; // Your client ID function App() { const [isAuthenticated, setIsAuthenticated] = useState(false); const [videos, setVideos] = useState([]); const [accessToken, setAccessToken] = useState(""); const [searchQuery, setSearchQuery] = useState(""); const handleLoginSuccess = (response) => { setIsAuthenticated(true); setAccessToken(response.accessToken); fetchVideos(response.accessToken, ""); // Hard-code the date filter }; const handleLoginFailure = (error) => { console.error("Login failed:", error); }; const fetchVideos = async (token, searchQuery = "") => { gapi.load("client", async () => { await gapi.client.init({ apiKey: API_KEY, discoveryDocs: [ "https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest", ], }); // Get the channelId of the authenticated user's YouTube account const response = await gapi.client.youtube.channels.list({ part: "snippet,contentDetails", mine: true, access_token: token, }); const channelId = response.result.items[0].id; try { // Fetch the videos based on search query and hardcoded date filter (2021) const videoListResponse = await gapi.client.youtube.search.list({ part: "snippet", channelId: channelId, maxResults: 20, q: searchQuery, // Add the search query to filter videos access_token: token, }); setVideos(videoListResponse.result.items); } catch (error) { console.error("Error fetching videos:", error); } }); }; const handleSearchChange = (event) => { setSearchQuery(event.target.value); }; const VideoItem = ({ video, onOpen }) => { const title = video.snippet.title || "No Title"; const videoId = video.id.videoId; // Ensure it's a video if (!videoId) return null; // If there's no valid videoId, do not render the button return ( <li className="list-group-item d-flex justify-content-between align-items-center"> <strong>{title}</strong> <div> <Button variant="primary" size="sm" onClick={() => onOpen(videoId)} className="me-2" > Open </Button> </div> </li> ); }; const VideoList = ({ videos, onOpen }) => { return ( <ul className="list-group"> {videos.map((video) => ( <VideoItem key={video.id.videoId} video={video} onOpen={onOpen} /> ))} </ul> ); }; const Auth = ({ clientId, onSuccess, onFailure }) => { return ( <GoogleLogin clientId={clientId} buttonText="Login with Google" onSuccess={onSuccess} onFailure={onFailure} scope="https://www.googleapis.com/auth/youtube.readonly" /> ); }; useEffect(() => { if (isAuthenticated) { fetchVideos(accessToken, searchQuery); // Use the hard-coded date for 2021 } }, [isAuthenticated, searchQuery]); return ( <div className="container mt-5"> <h1>Your Latest YouTube Videos (2021 Only)</h1> {!isAuthenticated ? ( <Auth clientId={CLIENT_ID} onSuccess={handleLoginSuccess} onFailure={handleLoginFailure} /> ) : ( <div> <Form inline className="mb-3"> {/* Search field */} <FormControl type="text" placeholder="Search videos" value={searchQuery} onChange={handleSearchChange} className="me-2" /> <Button variant="outline-primary" onClick={() => fetchVideos(accessToken, searchQuery)} > Search </Button> </Form> <VideoList videos={videos} onOpen={(videoId) => videoId && window.open(`https://www.youtube.com/watch?v=${videoId}`, "_blank") } /> </div> )} </div> ); } export default App; |