Browse Source

Add RSS feed creation functionality

Implement the ability to add new RSS feeds from the main feed tracking page.
gpt-engineer-app[bot] 6 months ago
parent
commit
de9dd84752
3 changed files with 242 additions and 2 deletions
  1. 216 0
      src/components/AddFeedModal.tsx
  2. 8 2
      src/components/Header.tsx
  3. 18 0
      src/pages/Index.tsx

+ 216 - 0
src/components/AddFeedModal.tsx

@@ -0,0 +1,216 @@
+
+import { useState } from 'react';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import { Textarea } from '@/components/ui/textarea';
+import {
+  Dialog,
+  DialogContent,
+  DialogDescription,
+  DialogFooter,
+  DialogHeader,
+  DialogTitle,
+} from '@/components/ui/dialog';
+import {
+  Form,
+  FormControl,
+  FormField,
+  FormItem,
+  FormLabel,
+  FormMessage,
+} from '@/components/ui/form';
+import { useForm } from 'react-hook-form';
+import { 
+  Globe, 
+  Rss, 
+  Play, 
+  Gamepad2,
+  Newspaper 
+} from 'lucide-react';
+import { NewsCategory } from '@/types/news';
+
+interface AddFeedModalProps {
+  isOpen: boolean;
+  onClose: () => void;
+  onAddFeed: (feedData: any) => void;
+  categories: NewsCategory[];
+}
+
+interface FeedFormData {
+  name: string;
+  url: string;
+  category: string;
+  description?: string;
+}
+
+const feedTypeOptions = [
+  { value: 'website', label: "D'un site web", icon: Globe, color: 'bg-blue-500' },
+  { value: 'rss-auto', label: "D'un flux RSS (automatique)", icon: Rss, color: 'bg-orange-500' },
+  { value: 'rss-manual', label: "D'un flux RSS (manuel)", icon: Rss, color: 'bg-yellow-500' },
+  { value: 'youtube', label: "D'une chaîne YouTube", icon: Play, color: 'bg-red-500' },
+  { value: 'steam', label: "D'un Jeu présent sur Steam", icon: Gamepad2, color: 'bg-gray-700' },
+];
+
+const AddFeedModal = ({ isOpen, onClose, onAddFeed, categories }: AddFeedModalProps) => {
+  const [selectedType, setSelectedType] = useState<string>('');
+  
+  const form = useForm<FeedFormData>({
+    defaultValues: {
+      name: '',
+      url: '',
+      category: '',
+      description: '',
+    },
+  });
+
+  const handleSubmit = (data: FeedFormData) => {
+    const feedData = {
+      ...data,
+      type: selectedType,
+      id: Date.now().toString(), // Simple ID generation
+    };
+    
+    onAddFeed(feedData);
+    form.reset();
+    setSelectedType('');
+    onClose();
+  };
+
+  const handleTypeSelect = (type: string) => {
+    setSelectedType(type);
+  };
+
+  const handleCancel = () => {
+    form.reset();
+    setSelectedType('');
+    onClose();
+  };
+
+  const selectedTypeOption = feedTypeOptions.find(option => option.value === selectedType);
+
+  return (
+    <Dialog open={isOpen} onOpenChange={onClose}>
+      <DialogContent className="sm:max-w-md">
+        <DialogHeader>
+          <DialogTitle className="flex items-center gap-2">
+            <Rss className="h-5 w-5" />
+            Ajouter un nouveau flux
+          </DialogTitle>
+          <DialogDescription>
+            Choisissez le type de flux que vous souhaitez ajouter
+          </DialogDescription>
+        </DialogHeader>
+
+        {!selectedType ? (
+          <div className="space-y-3">
+            {feedTypeOptions.map((option) => {
+              const IconComponent = option.icon;
+              return (
+                <Button
+                  key={option.value}
+                  variant="outline"
+                  className="w-full justify-start gap-3 h-auto p-4"
+                  onClick={() => handleTypeSelect(option.value)}
+                >
+                  <div className={`p-2 rounded ${option.color} text-white`}>
+                    <IconComponent className="h-4 w-4" />
+                  </div>
+                  <span>{option.label}</span>
+                </Button>
+              );
+            })}
+          </div>
+        ) : (
+          <Form {...form}>
+            <form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4">
+              <div className="flex items-center gap-2 p-3 bg-muted rounded-lg">
+                {selectedTypeOption && (
+                  <>
+                    <div className={`p-2 rounded ${selectedTypeOption.color} text-white`}>
+                      <selectedTypeOption.icon className="h-4 w-4" />
+                    </div>
+                    <span className="font-medium">{selectedTypeOption.label}</span>
+                  </>
+                )}
+              </div>
+
+              <FormField
+                control={form.control}
+                name="name"
+                render={({ field }) => (
+                  <FormItem>
+                    <FormLabel>Nom du flux</FormLabel>
+                    <FormControl>
+                      <Input 
+                        placeholder="Nom du flux..." 
+                        {...field} 
+                        required
+                      />
+                    </FormControl>
+                    <FormMessage />
+                  </FormItem>
+                )}
+              />
+
+              <FormField
+                control={form.control}
+                name="url"
+                render={({ field }) => (
+                  <FormItem>
+                    <FormLabel>URL</FormLabel>
+                    <FormControl>
+                      <Input 
+                        placeholder="https://..." 
+                        type="url"
+                        {...field} 
+                        required
+                      />
+                    </FormControl>
+                    <FormMessage />
+                  </FormItem>
+                )}
+              />
+
+              <FormField
+                control={form.control}
+                name="description"
+                render={({ field }) => (
+                  <FormItem>
+                    <FormLabel>Description (optionnel)</FormLabel>
+                    <FormControl>
+                      <Textarea 
+                        placeholder="Description du flux..."
+                        rows={3}
+                        {...field}
+                      />
+                    </FormControl>
+                    <FormMessage />
+                  </FormItem>
+                )}
+              />
+
+              <DialogFooter className="gap-2">
+                <Button type="button" variant="outline" onClick={handleCancel}>
+                  Annuler
+                </Button>
+                <Button type="submit">
+                  Ajouter le flux
+                </Button>
+              </DialogFooter>
+            </form>
+          </Form>
+        )}
+
+        {!selectedType && (
+          <DialogFooter>
+            <Button variant="outline" onClick={onClose}>
+              Annuler
+            </Button>
+          </DialogFooter>
+        )}
+      </DialogContent>
+    </Dialog>
+  );
+};
+
+export default AddFeedModal;

+ 8 - 2
src/components/Header.tsx

@@ -14,9 +14,10 @@ interface HeaderProps {
   searchQuery: string;
   onSearchChange: (query: string) => void;
   pinnedCount: number;
+  onAddFeedClick: () => void;
 }
 
-const Header = ({ searchQuery, onSearchChange, pinnedCount }: HeaderProps) => {
+const Header = ({ searchQuery, onSearchChange, pinnedCount, onAddFeedClick }: HeaderProps) => {
   return (
     <header className="border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 sticky top-0 z-50">
       <div className="container mx-auto px-4 py-4">
@@ -43,7 +44,12 @@ const Header = ({ searchQuery, onSearchChange, pinnedCount }: HeaderProps) => {
               />
             </div>
             
-            <Button variant="outline" size="sm" className="gap-2">
+            <Button 
+              variant="outline" 
+              size="sm" 
+              className="gap-2"
+              onClick={onAddFeedClick}
+            >
               <Plus className="h-4 w-4" />
               Ajouter un Flux
             </Button>

+ 18 - 0
src/pages/Index.tsx

@@ -5,6 +5,7 @@ import { NewsItem } from '@/types/news';
 import Header from '@/components/Header';
 import CategoryFilter from '@/components/CategoryFilter';
 import NewsCard from '@/components/NewsCard';
+import AddFeedModal from '@/components/AddFeedModal';
 import { Badge } from '@/components/ui/badge';
 import { Button } from '@/components/ui/button';
 import { RefreshCw, Filter } from 'lucide-react';
@@ -15,6 +16,7 @@ const Index = () => {
   const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
   const [searchQuery, setSearchQuery] = useState('');
   const [showFilters, setShowFilters] = useState(true);
+  const [isAddFeedModalOpen, setIsAddFeedModalOpen] = useState(false);
 
   const filteredNews = useMemo(() => {
     let filtered = news;
@@ -67,12 +69,21 @@ const Index = () => {
     toast.success("Flux actualisés");
   };
 
+  const handleAddFeed = (feedData: any) => {
+    console.log('Nouveau flux ajouté:', feedData);
+    toast.success(`Flux "${feedData.name}" ajouté avec succès!`);
+    
+    // Ici vous pourrez ajouter la logique pour envoyer les données à votre backend MySQL
+    // Par exemple: await api.addFeed(feedData);
+  };
+
   return (
     <div className="min-h-screen bg-background">
       <Header 
         searchQuery={searchQuery}
         onSearchChange={setSearchQuery}
         pinnedCount={pinnedCount}
+        onAddFeedClick={() => setIsAddFeedModalOpen(true)}
       />
       
       <main className="container mx-auto px-4 py-6">
@@ -166,6 +177,13 @@ const Index = () => {
           </div>
         </div>
       </main>
+
+      <AddFeedModal 
+        isOpen={isAddFeedModalOpen}
+        onClose={() => setIsAddFeedModalOpen(false)}
+        onAddFeed={handleAddFeed}
+        categories={categories}
+      />
     </div>
   );
 };