Zelyanoth commited on
Commit
2e2a2c3
·
1 Parent(s): 4f4ee62

source_checkerr

Browse files
frontend/src/pages/Posts.jsx CHANGED
@@ -1,5 +1,6 @@
1
  import React, { useState, useEffect } from 'react';
2
  import { useDispatch, useSelector } from 'react-redux';
 
3
  import {
4
  fetchPosts,
5
  generatePost,
@@ -10,11 +11,14 @@ import {
10
  clearError
11
  } from '../store/reducers/postsSlice';
12
  import { fetchAccounts } from '../store/reducers/accountsSlice';
 
13
 
14
  const Posts = () => {
15
  const dispatch = useDispatch();
 
16
  const { items: posts, loading, error } = useSelector(state => state.posts);
17
  const { items: accounts } = useSelector(state => state.accounts);
 
18
 
19
  const [selectedAccount, setSelectedAccount] = useState('');
20
  const [postContent, setPostContent] = useState('');
@@ -24,6 +28,7 @@ const Posts = () => {
24
  useEffect(() => {
25
  dispatch(fetchPosts());
26
  dispatch(fetchAccounts());
 
27
  dispatch(clearError());
28
  }, [dispatch]);
29
 
@@ -196,6 +201,37 @@ const Posts = () => {
196
  </div>
197
  )}
198
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  <div className="posts-content space-y-6 sm:space-y-8">
200
  {/* Post Creation Section */}
201
  <div className="post-creation-section bg-white/90 backdrop-blur-sm rounded-2xl p-4 sm:p-6 shadow-lg border border-gray-200/30 hover:shadow-xl transition-all duration-300 animate-slide-up">
@@ -226,7 +262,7 @@ const Posts = () => {
226
  <button
227
  className="btn btn-primary generate-button w-full bg-gradient-to-r from-gray-900 to-gray-800 text-white py-2.5 sm:py-3 px-4 sm:px-6 rounded-xl font-semibold hover:from-gray-800 hover:to-gray-900 transition-all duration-300 shadow-lg hover:shadow-xl disabled:opacity-60 disabled:cursor-not-allowed flex items-center justify-center space-x-2 touch-manipulation active:scale-95"
228
  onClick={handleGeneratePost}
229
- disabled={isGenerating}
230
  aria-busy={isGenerating}
231
  >
232
  {isGenerating ? (
@@ -237,6 +273,13 @@ const Posts = () => {
237
  </svg>
238
  <span className="text-xs sm:text-sm">Generating (may take 2-5 minutes)...</span>
239
  </>
 
 
 
 
 
 
 
240
  ) : (
241
  <>
242
  <svg className="w-4 h-4 sm:w-5 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -246,6 +289,11 @@ const Posts = () => {
246
  </>
247
  )}
248
  </button>
 
 
 
 
 
249
  {isGenerating && (
250
  <p className="text-xs text-gray-500 mt-2 text-center">
251
  Please wait while we generate your post. This may take 2-5 minutes.
@@ -294,7 +342,7 @@ const Posts = () => {
294
  <button
295
  type="submit"
296
  className="btn btn-primary create-button bg-gradient-to-r from-gray-900 to-gray-800 text-white py-2.5 sm:py-3 px-4 sm:px-6 rounded-xl font-semibold hover:from-gray-800 hover:to-gray-900 transition-all duration-300 shadow-lg hover:shadow-xl disabled:opacity-60 disabled:cursor-not-allowed h-fit flex items-center justify-center space-x-2 touch-manipulation active:scale-95"
297
- disabled={isCreating || !selectedAccount || !postContent.trim()}
298
  aria-busy={isCreating}
299
  >
300
  {isCreating ? (
@@ -305,6 +353,13 @@ const Posts = () => {
305
  </svg>
306
  <span className="text-xs sm:text-sm">Publishing...</span>
307
  </>
 
 
 
 
 
 
 
308
  ) : (
309
  <>
310
  <svg className="w-4 h-4 sm:w-5 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
 
1
  import React, { useState, useEffect } from 'react';
2
  import { useDispatch, useSelector } from 'react-redux';
3
+ import { useNavigate } from 'react-router-dom';
4
  import {
5
  fetchPosts,
6
  generatePost,
 
11
  clearError
12
  } from '../store/reducers/postsSlice';
13
  import { fetchAccounts } from '../store/reducers/accountsSlice';
14
+ import { fetchSources } from '../store/reducers/sourcesSlice';
15
 
16
  const Posts = () => {
17
  const dispatch = useDispatch();
18
+ const navigate = useNavigate();
19
  const { items: posts, loading, error } = useSelector(state => state.posts);
20
  const { items: accounts } = useSelector(state => state.accounts);
21
+ const { items: sources } = useSelector(state => state.sources);
22
 
23
  const [selectedAccount, setSelectedAccount] = useState('');
24
  const [postContent, setPostContent] = useState('');
 
28
  useEffect(() => {
29
  dispatch(fetchPosts());
30
  dispatch(fetchAccounts());
31
+ dispatch(fetchSources());
32
  dispatch(clearError());
33
  }, [dispatch]);
34
 
 
201
  </div>
202
  )}
203
 
204
+ {/* Info Message when no sources */}
205
+ {sources.length === 0 && !loading && (
206
+ <div className="mb-6 sm:mb-8 animate-fade-in">
207
+ <div className="bg-gradient-to-r from-yellow-50 to-amber-50 border border-yellow-200 rounded-xl p-4 sm:p-6 flex items-start space-x-3 sm:space-x-4">
208
+ <div className="flex-shrink-0">
209
+ <div className="w-8 h-8 sm:w-10 sm:h-10 bg-yellow-100 rounded-lg flex items-center justify-center">
210
+ <svg className="w-4 h-4 sm:w-6 sm:h-6 text-yellow-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
211
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
212
+ </svg>
213
+ </div>
214
+ </div>
215
+ <div className="flex-1">
216
+ <h3 className="text-base sm:text-lg font-semibold text-gray-900 mb-1 sm:mb-2">No RSS Sources Found</h3>
217
+ <p className="text-xs sm:text-sm text-gray-700 leading-relaxed mb-3">
218
+ You need to add at least one RSS source before generating posts.
219
+ RSS sources provide the content that will be used to generate your social media posts.
220
+ </p>
221
+ <button
222
+ onClick={() => navigate('/sources')}
223
+ className="btn btn-primary bg-gradient-to-r from-yellow-500 to-amber-600 text-white py-2 px-4 rounded-xl font-semibold hover:from-yellow-600 hover:to-amber-700 transition-all duration-300 shadow-md hover:shadow-lg flex items-center justify-center space-x-2 touch-manipulation"
224
+ >
225
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
226
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
227
+ </svg>
228
+ <span className="text-xs sm:text-sm">Add RSS Sources</span>
229
+ </button>
230
+ </div>
231
+ </div>
232
+ </div>
233
+ )}
234
+
235
  <div className="posts-content space-y-6 sm:space-y-8">
236
  {/* Post Creation Section */}
237
  <div className="post-creation-section bg-white/90 backdrop-blur-sm rounded-2xl p-4 sm:p-6 shadow-lg border border-gray-200/30 hover:shadow-xl transition-all duration-300 animate-slide-up">
 
262
  <button
263
  className="btn btn-primary generate-button w-full bg-gradient-to-r from-gray-900 to-gray-800 text-white py-2.5 sm:py-3 px-4 sm:px-6 rounded-xl font-semibold hover:from-gray-800 hover:to-gray-900 transition-all duration-300 shadow-lg hover:shadow-xl disabled:opacity-60 disabled:cursor-not-allowed flex items-center justify-center space-x-2 touch-manipulation active:scale-95"
264
  onClick={handleGeneratePost}
265
+ disabled={isGenerating || sources.length === 0}
266
  aria-busy={isGenerating}
267
  >
268
  {isGenerating ? (
 
273
  </svg>
274
  <span className="text-xs sm:text-sm">Generating (may take 2-5 minutes)...</span>
275
  </>
276
+ ) : sources.length === 0 ? (
277
+ <>
278
+ <svg className="w-4 h-4 sm:w-5 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
279
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
280
+ </svg>
281
+ <span className="text-xs sm:text-sm">No Sources</span>
282
+ </>
283
  ) : (
284
  <>
285
  <svg className="w-4 h-4 sm:w-5 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
 
289
  </>
290
  )}
291
  </button>
292
+ {sources.length === 0 && !isGenerating && (
293
+ <p className="text-xs text-yellow-600 mt-2 text-center">
294
+ You need to add RSS sources before generating content.
295
+ </p>
296
+ )}
297
  {isGenerating && (
298
  <p className="text-xs text-gray-500 mt-2 text-center">
299
  Please wait while we generate your post. This may take 2-5 minutes.
 
342
  <button
343
  type="submit"
344
  className="btn btn-primary create-button bg-gradient-to-r from-gray-900 to-gray-800 text-white py-2.5 sm:py-3 px-4 sm:px-6 rounded-xl font-semibold hover:from-gray-800 hover:to-gray-900 transition-all duration-300 shadow-lg hover:shadow-xl disabled:opacity-60 disabled:cursor-not-allowed h-fit flex items-center justify-center space-x-2 touch-manipulation active:scale-95"
345
+ disabled={isCreating || !selectedAccount || !postContent.trim() || sources.length === 0}
346
  aria-busy={isCreating}
347
  >
348
  {isCreating ? (
 
353
  </svg>
354
  <span className="text-xs sm:text-sm">Publishing...</span>
355
  </>
356
+ ) : sources.length === 0 ? (
357
+ <>
358
+ <svg className="w-4 h-4 sm:w-5 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
359
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
360
+ </svg>
361
+ <span className="text-xs sm:text-sm">No Sources</span>
362
+ </>
363
  ) : (
364
  <>
365
  <svg className="w-4 h-4 sm:w-5 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
frontend/src/pages/Schedule.jsx CHANGED
@@ -1,5 +1,6 @@
1
  import React, { useState, useEffect } from 'react';
2
  import { useDispatch, useSelector } from 'react-redux';
 
3
  import {
4
  fetchSchedules,
5
  createSchedule,
@@ -7,12 +8,15 @@ import {
7
  clearError
8
  } from '../store/reducers/schedulesSlice';
9
  import { fetchAccounts } from '../store/reducers/accountsSlice';
 
10
  import { formatScheduleForDisplay } from '../utils/timezoneUtils';
11
 
12
  const Schedule = () => {
13
  const dispatch = useDispatch();
 
14
  const { items: schedules, loading, error } = useSelector(state => state.schedules);
15
  const { items: accounts } = useSelector(state => state.accounts);
 
16
 
17
  const [selectedAccount, setSelectedAccount] = useState('');
18
  const [scheduleTime, setScheduleTime] = useState('18:00');
@@ -32,6 +36,7 @@ const Schedule = () => {
32
 
33
  dispatch(fetchSchedules());
34
  dispatch(fetchAccounts());
 
35
  dispatch(clearError());
36
  }, [dispatch]);
37
 
@@ -264,6 +269,37 @@ const Schedule = () => {
264
  </div>
265
  )}
266
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  {/* Schedule Creation Section */}
268
  <div className="schedule-creation-section bg-white/90 backdrop-blur-sm rounded-2xl p-4 sm:p-6 shadow-lg border border-gray-200/30 hover:shadow-xl transition-all duration-300 animate-slide-up">
269
  <div className="flex items-center justify-between mb-4 sm:mb-6">
@@ -359,7 +395,7 @@ const Schedule = () => {
359
  <button
360
  type="submit"
361
  className="btn btn-primary create-button bg-gradient-to-r from-blue-600 to-purple-600 text-white py-2.5 sm:py-3 px-6 sm:px-8 rounded-xl font-semibold hover:from-blue-700 hover:to-purple-700 transition-all duration-300 shadow-lg hover:shadow-xl disabled:opacity-60 disabled:cursor-not-allowed flex items-center justify-center space-x-2 touch-manipulation active:scale-95"
362
- disabled={isCreating || !selectedAccount || selectedDays.length === 0 || accounts.length === 0}
363
  aria-busy={isCreating}
364
  >
365
  {isCreating ? (
@@ -377,6 +413,13 @@ const Schedule = () => {
377
  </svg>
378
  <span className="text-xs sm:text-sm">No Accounts</span>
379
  </>
 
 
 
 
 
 
 
380
  ) : (
381
  <>
382
  <svg className="w-4 h-4 sm:w-5 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
 
1
  import React, { useState, useEffect } from 'react';
2
  import { useDispatch, useSelector } from 'react-redux';
3
+ import { useNavigate } from 'react-router-dom';
4
  import {
5
  fetchSchedules,
6
  createSchedule,
 
8
  clearError
9
  } from '../store/reducers/schedulesSlice';
10
  import { fetchAccounts } from '../store/reducers/accountsSlice';
11
+ import { fetchSources } from '../store/reducers/sourcesSlice';
12
  import { formatScheduleForDisplay } from '../utils/timezoneUtils';
13
 
14
  const Schedule = () => {
15
  const dispatch = useDispatch();
16
+ const navigate = useNavigate();
17
  const { items: schedules, loading, error } = useSelector(state => state.schedules);
18
  const { items: accounts } = useSelector(state => state.accounts);
19
+ const { items: sources } = useSelector(state => state.sources);
20
 
21
  const [selectedAccount, setSelectedAccount] = useState('');
22
  const [scheduleTime, setScheduleTime] = useState('18:00');
 
36
 
37
  dispatch(fetchSchedules());
38
  dispatch(fetchAccounts());
39
+ dispatch(fetchSources());
40
  dispatch(clearError());
41
  }, [dispatch]);
42
 
 
269
  </div>
270
  )}
271
 
272
+ {/* Info Message when no sources */}
273
+ {sources.length === 0 && !loading && (
274
+ <div className="mb-6 sm:mb-8 animate-fade-in">
275
+ <div className="bg-gradient-to-r from-yellow-50 to-amber-50 border border-yellow-200 rounded-xl p-4 sm:p-6 flex items-start space-x-3 sm:space-x-4">
276
+ <div className="flex-shrink-0">
277
+ <div className="w-8 h-8 sm:w-10 sm:h-10 bg-yellow-100 rounded-lg flex items-center justify-center">
278
+ <svg className="w-4 h-4 sm:w-6 sm:h-6 text-yellow-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
279
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
280
+ </svg>
281
+ </div>
282
+ </div>
283
+ <div className="flex-1">
284
+ <h3 className="text-base sm:text-lg font-semibold text-gray-900 mb-1 sm:mb-2">No RSS Sources Found</h3>
285
+ <p className="text-xs sm:text-sm text-gray-700 leading-relaxed mb-3">
286
+ You need to add at least one RSS source before creating schedules.
287
+ RSS sources provide the content that will be used for your scheduled posts.
288
+ </p>
289
+ <button
290
+ onClick={() => navigate('/sources')}
291
+ className="btn btn-primary bg-gradient-to-r from-yellow-500 to-amber-600 text-white py-2 px-4 rounded-xl font-semibold hover:from-yellow-600 hover:to-amber-700 transition-all duration-300 shadow-md hover:shadow-lg flex items-center justify-center space-x-2 touch-manipulation"
292
+ >
293
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
294
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
295
+ </svg>
296
+ <span className="text-xs sm:text-sm">Add RSS Sources</span>
297
+ </button>
298
+ </div>
299
+ </div>
300
+ </div>
301
+ )}
302
+
303
  {/* Schedule Creation Section */}
304
  <div className="schedule-creation-section bg-white/90 backdrop-blur-sm rounded-2xl p-4 sm:p-6 shadow-lg border border-gray-200/30 hover:shadow-xl transition-all duration-300 animate-slide-up">
305
  <div className="flex items-center justify-between mb-4 sm:mb-6">
 
395
  <button
396
  type="submit"
397
  className="btn btn-primary create-button bg-gradient-to-r from-blue-600 to-purple-600 text-white py-2.5 sm:py-3 px-6 sm:px-8 rounded-xl font-semibold hover:from-blue-700 hover:to-purple-700 transition-all duration-300 shadow-lg hover:shadow-xl disabled:opacity-60 disabled:cursor-not-allowed flex items-center justify-center space-x-2 touch-manipulation active:scale-95"
398
+ disabled={isCreating || !selectedAccount || selectedDays.length === 0 || accounts.length === 0 || sources.length === 0}
399
  aria-busy={isCreating}
400
  >
401
  {isCreating ? (
 
413
  </svg>
414
  <span className="text-xs sm:text-sm">No Accounts</span>
415
  </>
416
+ ) : sources.length === 0 ? (
417
+ <>
418
+ <svg className="w-4 h-4 sm:w-5 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
419
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
420
+ </svg>
421
+ <span className="text-xs sm:text-sm">No Sources</span>
422
+ </>
423
  ) : (
424
  <>
425
  <svg className="w-4 h-4 sm:w-5 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">