diff options
| author | A Farzat <a@farzat.xyz> | 2025-10-09 08:59:52 +0300 |
|---|---|---|
| committer | A Farzat <a@farzat.xyz> | 2025-10-09 08:59:52 +0300 |
| commit | 7e2a136db5921755a29fa5c9a1751028688c55cd (patch) | |
| tree | 372d972fe21cb25f6c441a994aa4db669c89010b /front-end | |
| parent | d1b1c055bb9ed49530e9a96fd34b3ada5899bbb5 (diff) | |
| download | csca5028-7e2a136db5921755a29fa5c9a1751028688c55cd.tar.gz csca5028-7e2a136db5921755a29fa5c9a1751028688c55cd.zip | |
Add last_viewed handling
Diffstat (limited to 'front-end')
| -rw-r--r-- | front-end/src/App.css | 31 | ||||
| -rw-r--r-- | front-end/src/App.jsx | 29 |
2 files changed, 58 insertions, 2 deletions
diff --git a/front-end/src/App.css b/front-end/src/App.css index 714d6fb..20d839e 100644 --- a/front-end/src/App.css +++ b/front-end/src/App.css @@ -376,6 +376,35 @@ body { transform: scale(1.05); } +.new-overlay { + position: absolute; + top: 8px; + right: 8px; + background: linear-gradient(135deg, #ff6b6b, #ff4757); + color: white; + padding: 4px 8px; + border-radius: 4px; + font-size: 0.7rem; + font-weight: bold; + text-transform: uppercase; + letter-spacing: 0.5px; + box-shadow: 0 2px 8px rgba(255, 107, 107, 0.4); + z-index: 2; + animation: pulse 2s infinite; +} + +@keyframes pulse { + 0% { + box-shadow: 0 2px 8px rgba(255, 107, 107, 0.4); + } + 50% { + box-shadow: 0 2px 16px rgba(255, 107, 107, 0.6); + } + 100% { + box-shadow: 0 2px 8px rgba(255, 107, 107, 0.4); + } +} + .duration-overlay { position: absolute; bottom: 8px; @@ -387,6 +416,7 @@ body { font-size: 0.8rem; font-weight: bold; backdrop-filter: blur(4px); + z-index: 2; } .play-button { @@ -399,6 +429,7 @@ body { text-shadow: 2px 2px 8px rgba(0, 0, 0, 0.7); opacity: 0.9; transition: all 0.3s ease; + z-index: 1; } .video-card:hover .play-button { diff --git a/front-end/src/App.jsx b/front-end/src/App.jsx index 104b561..da6057e 100644 --- a/front-end/src/App.jsx +++ b/front-end/src/App.jsx @@ -36,9 +36,10 @@ function App() { id: id, _id: subscription._id, type: type, - title: subscription.title || id, // Use title if available, fallback to ID + title: subscription.title, last_fetch: subscription.last_fetch, last_video_update: subscription.last_video_update, + last_viewed: subscription.last_viewed, new_vids: subscription.new_vids, time_between_fetches: subscription.time_between_fetches, videos: subscription.videos @@ -54,6 +55,23 @@ function App() { } }; + const setViewed = async (subscriptionId, viewedTime) => { + try { + const formData = new FormData(); + formData.append('_id', subscriptionId); + formData.append('viewed_time', viewedTime); + + await axios.post(`${API_BASE_URL}/set-viewed/`, formData, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }); + } catch (err) { + console.error('Error setting viewed time:', err); + // Don't show error to user as this is a background operation + } + }; + const fetchVideos = async (channelId) => { try { setLoading(true); @@ -69,6 +87,9 @@ function App() { if (response.data && Array.isArray(response.data)) { setVideos(response.data); + + const currentTime = new Date().toISOString(); + setViewed(subscription._id, currentTime); } else { throw new Error('Invalid response format'); } @@ -305,7 +326,7 @@ function App() { id="time-between-fetches" type="number" value={timeBetweenFetches} - onChange={(e) => setTimeBetweenFetches(parseInt(e.target.value) || 300)} + onChange={(e) => setTimeBetweenFetches(parseInt(e.target.value) || 0)} min="60" max="86400" className="subscription-input" @@ -387,6 +408,10 @@ function App() { <div className="duration-overlay"> {formatDuration(video.duration)} </div> + {channels.find(ch => ch.id === selectedChannelId)?.last_viewed && + new Date(video.published) > new Date(channels.find(ch => ch.id === selectedChannelId).last_viewed) && ( + <div className="new-overlay">NEW</div> + )} <div className="play-button">▶</div> </div> |
