diff --git a/src/components/ui/Toast.jsx b/src/components/ui/Toast.jsx new file mode 100644 index 0000000..06b4129 --- /dev/null +++ b/src/components/ui/Toast.jsx @@ -0,0 +1,25 @@ +import React, { useEffect } from "react"; + +const Toast = ({ message, type = "success", onClose }) => { + useEffect(() => { + const timer = setTimeout(onClose, 3000); + return () => clearTimeout(timer); + }, [onClose]); + + return ( +
+ {type === "success" ? "✅" : "❌"} + {message} +
+ ); +}; + +export default Toast; \ No newline at end of file diff --git a/src/pages/Profile.jsx b/src/pages/Profile.jsx index c207c17..26f0739 100644 --- a/src/pages/Profile.jsx +++ b/src/pages/Profile.jsx @@ -1,4 +1,5 @@ import React, { useState, useEffect } from "react"; +import Toast from "../components/ui/Toast"; import LottiePlayer from "../components/ui/LottiePlayer"; import { MapPin, @@ -26,7 +27,7 @@ export const Profile = () => { const { userData, user, setUserData } = useAuth(); const [copied, setCopied] = useState(false); const [rank, setRank] = useState("Loading..."); - + const [toast, setToast] = useState(null); // Social links edit states const [editingSocial, setEditingSocial] = useState(null); const [editValue, setEditValue] = useState(""); @@ -82,9 +83,38 @@ export const Profile = () => { }; // Handle social link update - const handleUpdateSocialLink = async (type, value) => { +const handleUpdateSocialLink = async (type, value) => { if (!user) return; - + + // Validate input before updating + if (type === "linkedin") { + if (value && value.trim()) { + const linkedinPattern = /^(https?:\/\/)?(www\.)?linkedin\.com\/in\/[\w\-]+\/?$/i; + const rawVal = value.trim(); + const testVal = rawVal.startsWith('http') ? rawVal : 'https://' + rawVal; + if (!linkedinPattern.test(testVal)) { + setToast({ message: "Invalid LinkedIn URL. Use format: linkedin.com/in/username", type: "error" }); + return; + } + } + } else if (type === "instagram") { + if (value && value.trim()) { + const igPattern = /^@?[\w](?!.*?\.{2})[\w.]{1,28}[\w]$/; + if (!igPattern.test(value.trim())) { + setToast({ message: "Invalid Instagram username.", type: "error" }); + return; + } + } + } else if (type === "discord") { + if (value && value.trim()) { + const discordPattern = /^.{3,32}(#\d{4})?$/; + if (!discordPattern.test(value.trim())) { + setToast({ message: "Invalid Discord username.", type: "error" }); + return; + } + } + } + setUpdating(true); try { const userRef = doc(db, "users", user.uid); @@ -138,10 +168,10 @@ export const Profile = () => { setEditingSocial(null); setEditValue(""); - alert(`${type.charAt(0).toUpperCase() + type.slice(1)} updated successfully!`); + setToast({ message: `${type.charAt(0).toUpperCase() + type.slice(1)} updated successfully!`, type: "success" }); } catch (err) { console.error("Error updating social link:", err); - alert(`Failed to update ${type}. Please try again.`); + setToast({ message: `Failed to update ${type}. Please try again.`, type: "error" }); } finally { setUpdating(false); }