diff --git a/platforms/dreamSync/.gitignore b/platforms/dreamSync/.gitignore new file mode 100644 index 00000000..f9ba7f8b --- /dev/null +++ b/platforms/dreamSync/.gitignore @@ -0,0 +1,6 @@ +node_modules +dist +.DS_Store +server/public +vite.config.ts.* +*.tar.gz \ No newline at end of file diff --git a/platforms/dreamSync/client/index.html b/platforms/dreamSync/client/index.html new file mode 100644 index 00000000..4b4d09e3 --- /dev/null +++ b/platforms/dreamSync/client/index.html @@ -0,0 +1,13 @@ + + + + + + + +
+ + + + + \ No newline at end of file diff --git a/platforms/dreamSync/client/src/App.tsx b/platforms/dreamSync/client/src/App.tsx new file mode 100644 index 00000000..4929bc6f --- /dev/null +++ b/platforms/dreamSync/client/src/App.tsx @@ -0,0 +1,63 @@ +import { Switch, Route } from "wouter"; +import { queryClient } from "./lib/queryClient"; +import { QueryClientProvider } from "@tanstack/react-query"; +import { Toaster } from "@/components/ui/toaster"; +import { TooltipProvider } from "@/components/ui/tooltip"; +import { useAuth } from "@/hooks/useAuth"; +import { Heart } from "lucide-react"; +import NotFound from "@/pages/not-found"; +import Login from "@/pages/login"; +import Dashboard from "@/pages/dashboard"; +import Profile from "@/pages/profile"; +import MatchesNew from "@/pages/matches-new"; +import Suggestions from "@/pages/suggestions"; +import Wishlist from "@/pages/wishlist"; +import WishlistItem from "@/pages/wishlist-item"; + +function Router() { + const { isAuthenticated, isLoading } = useAuth(); + + if (isLoading) { + return ( +
+
+
+ +
+

Loading DreamSync...

+
+
+ ); + } + + return ( + + {!isAuthenticated ? ( + + ) : ( + <> + + + + + + + + )} + + + ); +} + +function App() { + return ( + + + + + + + ); +} + +export default App; diff --git a/platforms/dreamSync/client/src/components/add-wishlist-modal.tsx b/platforms/dreamSync/client/src/components/add-wishlist-modal.tsx new file mode 100644 index 00000000..3a636c42 --- /dev/null +++ b/platforms/dreamSync/client/src/components/add-wishlist-modal.tsx @@ -0,0 +1,234 @@ +import { useState, useEffect } from "react"; +import { useMutation } from "@tanstack/react-query"; +import { useLocation } from "wouter"; +import { useToast } from "@/hooks/use-toast"; +import { apiRequest, queryClient } from "@/lib/queryClient"; +import { isUnauthorizedError } from "@/lib/authUtils"; +import { Dialog, DialogContent } from "@/components/ui/dialog"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; +import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; +import { Star, Plus, Loader2, ChevronDown } from "lucide-react"; +import type { WishlistItem } from "@shared/schema"; + +interface AddWishlistModalProps { + open: boolean; + onOpenChange: (open: boolean) => void; + editingItem?: WishlistItem | null; +} + +export default function AddWishlistModal({ open, onOpenChange, editingItem }: AddWishlistModalProps) { + const { toast } = useToast(); + const [, setLocation] = useLocation(); + + // Form state + const [title, setTitle] = useState(editingItem?.title || ""); + const [description, setDescription] = useState(editingItem?.description || ""); + const [priority, setPriority] = useState(editingItem?.priority || "medium"); + + // Reset form when modal opens/closes or editing item changes + useEffect(() => { + if (open) { + setTitle(editingItem?.title || ""); + setDescription(editingItem?.description || ""); + setPriority(editingItem?.priority || "medium"); + } + }, [open, editingItem]); + + const resetForm = () => { + setTitle(""); + setDescription(""); + setPriority("medium"); + }; + + // Add/Update wishlist item mutation + const wishlistMutation = useMutation({ + mutationFn: async () => { + const itemData = { title, description, priority }; + + if (editingItem) { + await apiRequest("PUT", `/api/wishlist/${editingItem.id}`, itemData); + } else { + await apiRequest("POST", "/api/wishlist", itemData); + } + }, + onSuccess: (data) => { + queryClient.invalidateQueries({ queryKey: ["/api/profile"] }); + toast({ + title: "Success", + description: editingItem ? "Wishlist item updated successfully!" : "Wishlist item added successfully!" + }); + resetForm(); + onOpenChange(false); + + // Redirect to wishlist page with new item highlighted + if (!editingItem) { + setLocation("/wishlist?highlight=new"); + } + }, + onError: (error) => { + if (isUnauthorizedError(error)) { + toast({ + title: "Unauthorized", + description: "You are logged out. Logging in again...", + variant: "destructive", + }); + setTimeout(() => { + window.location.href = "/api/login"; + }, 500); + return; + } + toast({ + title: "Error", + description: `Failed to ${editingItem ? 'update' : 'add'} wishlist item. Please try again.`, + variant: "destructive", + }); + }, + }); + + const handleSubmit = () => { + if (!title.trim()) { + toast({ + title: "Validation Error", + description: "Please fill in the title field.", + variant: "destructive", + }); + return; + } + wishlistMutation.mutate(); + }; + + const handleCancel = () => { + resetForm(); + onOpenChange(false); + }; + + return ( + + + {/* Header */} +
+
+ +
+

+ {editingItem ? "Edit Wishlist Item" : "Add Wishlist Item"} +

+

+ {editingItem ? "Update your wishlist item details" : "Share what you're looking to achieve or acquire"} +

+
+ + {/* Form Content */} +
+ {/* Title and Priority Row */} +
+
+
+
+ +
+ +
+
+ setTitle(e.target.value)} + placeholder="Learn Spanish, Find a mentor..." + className="border-0 bg-white/70 backdrop-blur-sm shadow-sm focus:ring-2 focus:ring-blue-200 focus:bg-white transition-all duration-200" + /> +
+
+ +
+
+
+ +
+ +
+
+ + + + + + setPriority("urgent")}> + 🔥 Urgent! + + setPriority("high")}> + High Priority + + setPriority("medium")}> + Medium Priority + + setPriority("low")}> + Low Priority + + + +
+
+
+ + {/* Description */} +
+
+
+ +
+ +
+
+