diff --git a/backend/src/controllers/auth.controller.js b/backend/src/controllers/auth.controller.js index 303b0beb..6a712e0a 100644 --- a/backend/src/controllers/auth.controller.js +++ b/backend/src/controllers/auth.controller.js @@ -89,50 +89,6 @@ export const signup = async (req, res) => { ), })) ); - // Test-only bypass. It requires an explicit opt-in and can never run in - // production, even if the environment flag is set accidentally. - const isEmailVerificationBypassed = - process.env.NODE_ENV === "development" && - process.env.BYPASS_EMAIL_VERIFICATION === "true"; - - if (isEmailVerificationBypassed) { - // Auto-verify the user and log them in immediately - const newUser = await User.create({ - fullName, - email: normalizedEmail, - password: hashedPassword, - securityQuestions: hashedQuestions, - role: "user", - isVerified: true, // skip email verification - }); - - const token = generateToken(newUser._id); - const refreshToken = generateRefreshToken(newUser._id); - const refreshTokenHash = crypto.createHash("sha256").update(refreshToken).digest("hex"); - newUser.refreshTokenHash = refreshTokenHash; - await newUser.save(); - - res.cookie("refreshToken", refreshToken, { - httpOnly: true, - sameSite: "strict", - secure: false, - maxAge: 7 * 24 * 60 * 60 * 1000, - }); - - console.log("[DEV MODE] User auto-verified, no OTP email sent."); - - return res.status(201).json({ - _id: newUser._id, - fullName: newUser.fullName, - email: newUser.email, - profilePic: newUser.profilePic, - role: newUser.role, - token, - message: "[DEV] Account created and verified automatically (dev mode).", - }); - } - // --- END DEV MODE BYPASS --- - const verificationOtp = crypto.randomInt(100000, 1000000).toString(); const hashedVerificationOtp = await bcrypt.hash( diff --git a/backend/src/controllers/message.controller.js b/backend/src/controllers/message.controller.js index 4560e4f0..97f9c996 100644 --- a/backend/src/controllers/message.controller.js +++ b/backend/src/controllers/message.controller.js @@ -1,10 +1,10 @@ import mongoose from "mongoose"; -import User from "../models/user.model.js"; -import Message from "../models/message.model.js"; -import Group from "../models/group.model.js"; import cloudinary from "../lib/cloudinary.js"; -import { emitToUser, io } from "../lib/socket.js"; import analyzeMessage from "../lib/mlService.js"; +import { emitToUser, io } from "../lib/socket.js"; +import Group from "../models/group.model.js"; +import Message from "../models/message.model.js"; +import User from "../models/user.model.js"; export const updateChatWallpaper = async (req, res) => { try { @@ -90,7 +90,7 @@ export const getMessages = async (req, res) => { deletedForEveryone: false, deletedFor: { $ne: myId }, }) - .populate("replyTo", "text image senderId") + .populate("replyTo", "text image sticker senderId") .sort({ createdAt: 1 }); await Message.updateMany( @@ -117,7 +117,7 @@ export const getMessages = async (req, res) => { export const sendMessage = async (req, res) => { try { - const { text, image, audio, file, replyTo } = req.body; + const { text, image, audio, file, sticker, replyTo } = req.body; const { id: receiverId } = req.params; const senderId = req.user._id; @@ -137,7 +137,7 @@ export const sendMessage = async (req, res) => { }); } - if (!text && !image && !audio && !file) { + if (!text && !image && !audio && !file && !sticker) { return res.status(400).json({ message: "Message cannot be empty" }); } @@ -189,6 +189,7 @@ export const sendMessage = async (req, res) => { image: imageUrl, audio: audioUrl, file: fileData, + sticker: sticker || "", replyTo: replyTo || null, status: "sent", @@ -201,7 +202,7 @@ export const sendMessage = async (req, res) => { message = await message.populate({ path: "replyTo", - select: "text image senderId", + select: "text image sticker senderId", populate: { path: "senderId", select: "fullName profilePic", @@ -249,7 +250,7 @@ export const getGroupMessages = async (req, res) => { deletedFor: { $ne: userId }, }) .populate("senderId", "fullName profilePic") - .populate("replyTo", "text image senderId") + .populate("replyTo", "text image sticker senderId") .sort({ createdAt: 1 }); res.status(200).json(messages); @@ -262,7 +263,7 @@ export const sendGroupMessage = async (req, res) => { try { const { groupId } = req.params; const senderId = req.user._id; - const { text, image, audio, file, replyTo } = req.body; + const { text, image, audio, file, sticker, replyTo } = req.body; if (!mongoose.Types.ObjectId.isValid(groupId)) { return res.status(400).json({ message: "Invalid group id" }); @@ -281,6 +282,10 @@ export const sendGroupMessage = async (req, res) => { if (!isMember) return res.status(403).json({ message: "Not a group member" }); + if (!text && !image && !audio && !file && !sticker) { + return res.status(400).json({ message: "Message cannot be empty" }); + } + let imageUrl = ""; let audioUrl = ""; let fileData = null; @@ -329,6 +334,7 @@ export const sendGroupMessage = async (req, res) => { image: imageUrl, audio: audioUrl, file: fileData, + sticker: sticker || "", replyTo: replyTo || null, status: "sent", @@ -449,6 +455,7 @@ export const forwardMessage = async (req, res) => { image: originalMessage.image, audio: originalMessage.audio, file: safeFile, + sticker: originalMessage.sticker || "", isForwarded: true, originalMessageId: originalMessage._id, }); diff --git a/backend/src/controllers/sticker.controller.js b/backend/src/controllers/sticker.controller.js new file mode 100644 index 00000000..314c3f5a --- /dev/null +++ b/backend/src/controllers/sticker.controller.js @@ -0,0 +1,188 @@ +import User from "../models/user.model.js"; + +// Built-in sticker packs definition (also served via API for dynamic pack extensions) +export const BUILTIN_STICKER_PACKS = [ + { + id: "reactions", + name: "Reactions", + icon: "😂", + category: "Emotions", + stickers: [ + { id: "mindblown", name: "Mind Blown", url: "/stickers/reactions/mindblown.svg", tags: ["mindblown", "shock", "wow", "explode", "omg"] }, + { id: "laughing", name: "Laughing", url: "/stickers/reactions/laughing.svg", tags: ["laugh", "lol", "haha", "rofl", "joy"] }, + { id: "crying", name: "Crying", url: "/stickers/reactions/crying.svg", tags: ["cry", "sad", "tears", "sob", "upset"] }, + { id: "party", name: "Party Time", url: "/stickers/reactions/party.svg", tags: ["party", "celebrate", "confetti", "yay", "cheers"] }, + { id: "cool", name: "Cool Sunglasses", url: "/stickers/reactions/cool.svg", tags: ["cool", "sunglasses", "chill", "boss", "swag"] }, + { id: "heart_eyes", name: "Heart Eyes", url: "/stickers/reactions/heart_eyes.svg", tags: ["love", "heart", "eyes", "crush", "cute"] }, + { id: "fire", name: "On Fire", url: "/stickers/reactions/fire.svg", tags: ["fire", "lit", "hot", "flame", "awesome"] }, + { id: "facepalm", name: "Facepalm", url: "/stickers/reactions/facepalm.svg", tags: ["facepalm", "smh", "disappointed", "duh", "oops"] }, + { id: "thinking", name: "Thinking", url: "/stickers/reactions/thinking.svg", tags: ["think", "hmm", "ponder", "wonder", "curious"] }, + { id: "shocked", name: "Shocked", url: "/stickers/reactions/shocked.svg", tags: ["shock", "gasp", "scared", "fear", "omg"] }, + { id: "angry", name: "Angry", url: "/stickers/reactions/angry.svg", tags: ["angry", "mad", "rage", "furious", "annoyed"] }, + { id: "angel", name: "Innocent Angel", url: "/stickers/reactions/angel.svg", tags: ["angel", "innocent", "good", "halo", "pure"] }, + ], + }, + { + id: "pepe_memes", + name: "Pepe & Memes", + icon: "🐸", + category: "Memes", + stickers: [ + { id: "pepe_happy", name: "Pepe Happy", url: "/stickers/memes/pepe_happy.svg", tags: ["pepe", "happy", "smile", "feelsgood", "frog"] }, + { id: "pepe_sad", name: "Pepe Sad", url: "/stickers/memes/pepe_sad.svg", tags: ["pepe", "sad", "cry", "feelsbadman", "rain"] }, + { id: "pepe_hype", name: "Pepe Hype", url: "/stickers/memes/pepe_hype.svg", tags: ["pepe", "hype", "party", "dance", "energy"] }, + { id: "pepe_smart", name: "Big Brain Pepe", url: "/stickers/memes/pepe_smart.svg", tags: ["pepe", "brain", "smart", "genius", "iq"] }, + { id: "doge_wow", name: "Doge Wow", url: "/stickers/memes/doge_wow.svg", tags: ["doge", "wow", "shiba", "dog", "meme"] }, + { id: "score_100", name: "100 Percent", url: "/stickers/memes/score_100.svg", tags: ["100", "score", "perfect", "facts", "real"] }, + { id: "gg_wp", name: "GG Well Played", url: "/stickers/memes/gg_wp.svg", tags: ["gg", "game", "win", "gamer", "wp"] }, + { id: "stonks", name: "Stonks Up", url: "/stickers/memes/stonks.svg", tags: ["stonks", "profit", "money", "up", "crypto"] }, + { id: "popcat", name: "Pop Cat", url: "/stickers/memes/popcat.svg", tags: ["popcat", "cat", "mouth", "pop", "meme"] }, + { id: "bruh", name: "Bruh Moment", url: "/stickers/memes/bruh.svg", tags: ["bruh", "moment", "what", "bro", "meme"] }, + ], + }, + { + id: "cute_animals", + name: "Cute Animals", + icon: "🐱", + category: "Animals", + stickers: [ + { id: "cat_heart", name: "Cat Love", url: "/stickers/animals/cat_heart.svg", tags: ["cat", "love", "heart", "kitty", "purr"] }, + { id: "cat_laptop", name: "Coder Cat", url: "/stickers/animals/cat_laptop.svg", tags: ["cat", "laptop", "code", "work", "busy"] }, + { id: "dog_happy", name: "Happy Pup", url: "/stickers/animals/dog_happy.svg", tags: ["dog", "pup", "wag", "happy", "cute"] }, + { id: "fox_sleeping", name: "Sleepy Fox", url: "/stickers/animals/fox_sleeping.svg", tags: ["fox", "sleep", "rest", "night", "bed"] }, + { id: "bear_hug", name: "Bear Hug", url: "/stickers/animals/bear_hug.svg", tags: ["bear", "hug", "love", "cuddle", "friend"] }, + { id: "bunny_cheer", name: "Cheering Bunny", url: "/stickers/animals/bunny_cheer.svg", tags: ["bunny", "rabbit", "hop", "cheer", "jump"] }, + { id: "panda_bamboo", name: "Panda Munch", url: "/stickers/animals/panda_bamboo.svg", tags: ["panda", "eat", "food", "cute", "bamboo"] }, + { id: "penguin_waddle", name: "Waddling Penguin", url: "/stickers/animals/penguin_waddle.svg", tags: ["penguin", "walk", "cold", "cute", "bird"] }, + ], + }, + { + id: "anime_chibi", + name: "Anime & Chibi", + icon: "✨", + category: "Anime", + stickers: [ + { id: "chibi_sparkle", name: "Sparkle Eyes", url: "/stickers/anime/chibi_sparkle.svg", tags: ["anime", "sparkle", "eyes", "star", "chibi"] }, + { id: "chibi_rage", name: "Chibi Rage", url: "/stickers/anime/chibi_rage.svg", tags: ["anime", "rage", "anger", "flame", "chibi"] }, + { id: "chibi_sweat", name: "Nervous Sweat", url: "/stickers/anime/chibi_sweat.svg", tags: ["anime", "nervous", "sweat", "awkward", "oops"] }, + { id: "chibi_blush", name: "Kawaii Blush", url: "/stickers/anime/chibi_blush.svg", tags: ["anime", "blush", "kawaii", "shy", "cute"] }, + { id: "chibi_peace", name: "Peace Sign", url: "/stickers/anime/chibi_peace.svg", tags: ["anime", "peace", "victory", "pose", "v"] }, + { id: "chibi_sleepy", name: "Sleepy Chibi", url: "/stickers/anime/chibi_sleepy.svg", tags: ["anime", "sleep", "zzz", "tired", "chibi"] }, + { id: "chibi_gaming", name: "Pro Gamer", url: "/stickers/anime/chibi_gaming.svg", tags: ["anime", "game", "controller", "gamer", "play"] }, + { id: "chibi_coffee", name: "Coffee Time", url: "/stickers/anime/chibi_coffee.svg", tags: ["anime", "coffee", "morning", "tea", "drink"] }, + ], + }, + { + id: "vibes_gestures", + name: "Vibes & Gestures", + icon: "✌️", + category: "Gestures", + stickers: [ + { id: "thumbs_up", name: "Thumbs Up", url: "/stickers/vibes/thumbs_up.svg", tags: ["thumbsup", "ok", "yes", "like", "agree"] }, + { id: "heart_hands", name: "Heart Hands", url: "/stickers/vibes/heart_hands.svg", tags: ["heart", "hands", "love", "kpop", "care"] }, + { id: "high_five", name: "High Five", url: "/stickers/vibes/high_five.svg", tags: ["highfive", "team", "celebrate", "slap", "hands"] }, + { id: "peace_out", name: "Peace Sign", url: "/stickers/vibes/peace_out.svg", tags: ["peace", "vibe", "bye", "chill", "cool"] }, + { id: "clapping", name: "Clapping", url: "/stickers/vibes/clapping.svg", tags: ["clap", "applause", "bravo", "great", "cheer"] }, + { id: "rocket_blast", name: "Rocket Launch", url: "/stickers/vibes/rocket_blast.svg", tags: ["rocket", "launch", "moon", "speed", "fast"] }, + { id: "sparkle_star", name: "Super Star", url: "/stickers/vibes/sparkle_star.svg", tags: ["star", "sparkle", "gold", "shine", "winner"] }, + { id: "coffee_mug", name: "Fresh Coffee", url: "/stickers/vibes/coffee_mug.svg", tags: ["coffee", "cup", "morning", "fuel", "tea"] }, + ], + }, +]; + +const ALL_VALID_STICKER_URLS = new Set( + BUILTIN_STICKER_PACKS.flatMap((pack) => pack.stickers.map((s) => s.url)) +); + +// GET /api/stickers/packs +export const getStickerPacks = async (req, res) => { + try { + res.status(200).json({ packs: BUILTIN_STICKER_PACKS }); + } catch (error) { + console.error("getStickerPacks error:", error); + res.status(500).json({ message: "Failed to load sticker packs" }); + } +}; + +// GET /api/stickers/user-data +export const getUserStickerData = async (req, res) => { + try { + const user = await User.findById(req.user._id).select("favoriteStickers recentStickers"); + if (!user) { + return res.status(404).json({ message: "User not found" }); + } + + res.status(200).json({ + favoriteStickers: user.favoriteStickers || [], + recentStickers: user.recentStickers || [], + }); + } catch (error) { + console.error("getUserStickerData error:", error); + res.status(500).json({ message: "Failed to load user sticker data" }); + } +}; + +// POST /api/stickers/favorites/toggle +export const toggleFavoriteSticker = async (req, res) => { + try { + const { stickerUrl } = req.body; + if (!stickerUrl || typeof stickerUrl !== "string" || !ALL_VALID_STICKER_URLS.has(stickerUrl)) { + return res.status(400).json({ message: "Valid stickerUrl from official sticker packs is required" }); + } + + const user = await User.findById(req.user._id); + if (!user) { + return res.status(404).json({ message: "User not found" }); + } + + const currentFavorites = user.favoriteStickers || []; + const exists = currentFavorites.includes(stickerUrl); + + let updatedFavorites; + if (exists) { + updatedFavorites = currentFavorites.filter((url) => url !== stickerUrl); + } else { + updatedFavorites = [stickerUrl, ...currentFavorites]; + } + + user.favoriteStickers = updatedFavorites; + await user.save(); + + res.status(200).json({ + favoriteStickers: user.favoriteStickers, + isFavorited: !exists, + }); + } catch (error) { + console.error("toggleFavoriteSticker error:", error); + res.status(500).json({ message: "Failed to toggle favorite sticker" }); + } +}; + +// POST /api/stickers/recents +export const addRecentSticker = async (req, res) => { + try { + const { stickerUrl } = req.body; + if (!stickerUrl || typeof stickerUrl !== "string" || !ALL_VALID_STICKER_URLS.has(stickerUrl)) { + return res.status(400).json({ message: "Valid stickerUrl from official sticker packs is required" }); + } + + const user = await User.findById(req.user._id); + if (!user) { + return res.status(404).json({ message: "User not found" }); + } + + const currentRecents = user.recentStickers || []; + // Place at front, deduplicate, and limit to max 30 items + const filtered = currentRecents.filter((url) => url !== stickerUrl); + user.recentStickers = [stickerUrl, ...filtered].slice(0, 30); + + await user.save(); + + res.status(200).json({ + recentStickers: user.recentStickers, + }); + } catch (error) { + console.error("addRecentSticker error:", error); + res.status(500).json({ message: "Failed to add recent sticker" }); + } +}; diff --git a/backend/src/index.js b/backend/src/index.js index 5d3e05ce..c556df16 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -1,26 +1,27 @@ -import express from "express"; -import dotenv from "dotenv"; import cookieParser from "cookie-parser"; import cors from "cors"; +import dotenv from "dotenv"; +import express from "express"; import path from "path"; import { connectDB } from "./lib/db.js"; import { app, server } from "./lib/socket.js"; +import adminRoutes from "./routes/admin.routes.js"; +import aiRoutes from "./routes/ai.routes.js"; import authRoutes from "./routes/auth.route.js"; -import messageRoutes from "./routes/message.route.js"; +import gifRoutes from "./routes/gif.routes.js"; import groupRoutes from "./routes/group.routes.js"; -import aiRoutes from "./routes/ai.routes.js"; -import seedAIUser from "./seeds/seedAIUser.js"; -import statusRoutes from "./routes/status.routes.js"; -import adminRoutes from "./routes/admin.routes.js"; +import messageRoutes from "./routes/message.route.js"; +import pollRoutes from "./routes/poll.routes.js"; import reportRoutes from "./routes/report.routes.js"; -import gifRoutes from "./routes/gif.routes.js"; +import statusRoutes from "./routes/status.routes.js"; +import stickerRoutes from "./routes/sticker.routes.js"; import userRoutes from "./routes/user.route.js"; -import pollRoutes from "./routes/poll.routes.js"; +import seedAIUser from "./seeds/seedAIUser.js"; dotenv.config(); - const PORT = process.env.PORT || 5000; const __dirname = path.resolve(); + app.set("trust proxy", 1); app.use( @@ -33,9 +34,7 @@ app.use( credentials: true, }) ); - // app.options("*", cors()); - app.use(express.json({ limit: "50mb" })); app.use(express.urlencoded({ extended: true, limit: "50mb" })); app.use(cookieParser()); @@ -49,11 +48,11 @@ app.use("/api/admin", adminRoutes); app.use("/api/reports", reportRoutes); app.use("/api/gif", gifRoutes); app.use("/api/users", userRoutes); +app.use("/api/stickers", stickerRoutes); app.use("/api/polls", pollRoutes); if (process.env.NODE_ENV === "production") { app.use(express.static(path.join(__dirname, "../frontend/dist"))); - app.get("*", (req, res) => { res.sendFile( path.join(__dirname, "../frontend", "dist", "index.html") @@ -64,7 +63,6 @@ if (process.env.NODE_ENV === "production") { const startServer = async () => { await connectDB(); await seedAIUser(); - server.listen(PORT, () => { console.log(`Server running on PORT: ${PORT}`); }); diff --git a/backend/src/models/message.model.js b/backend/src/models/message.model.js index 57cc1e07..5a08bd05 100644 --- a/backend/src/models/message.model.js +++ b/backend/src/models/message.model.js @@ -41,6 +41,11 @@ const messageSchema = new mongoose.Schema( default: "", }, + sticker: { + type: String, + default: "", + }, + // Reply to message replyTo: { type: mongoose.Schema.Types.ObjectId, diff --git a/backend/src/models/user.model.js b/backend/src/models/user.model.js index d4a315ed..ae133863 100644 --- a/backend/src/models/user.model.js +++ b/backend/src/models/user.model.js @@ -101,6 +101,16 @@ const userSchema = new mongoose.Schema( default: [], }, + favoriteStickers: { + type: [String], + default: [], + }, + + recentStickers: { + type: [String], + default: [], + }, + // Security Questions (Max 3) securityQuestions: { type: [securityQuestionSchema], diff --git a/backend/src/routes/sticker.routes.js b/backend/src/routes/sticker.routes.js new file mode 100644 index 00000000..bc271ead --- /dev/null +++ b/backend/src/routes/sticker.routes.js @@ -0,0 +1,17 @@ +import express from "express"; +import { + getStickerPacks, + getUserStickerData, + toggleFavoriteSticker, + addRecentSticker, +} from "../controllers/sticker.controller.js"; +import { protectRoute } from "../middleware/auth.middleware.js"; + +const router = express.Router(); + +router.get("/packs", protectRoute, getStickerPacks); +router.get("/user-data", protectRoute, getUserStickerData); +router.post("/favorites/toggle", protectRoute, toggleFavoriteSticker); +router.post("/recents", protectRoute, addRecentSticker); + +export default router; diff --git a/frontend/public/stickers/animals/bear_hug.svg b/frontend/public/stickers/animals/bear_hug.svg new file mode 100644 index 00000000..9a3148fc --- /dev/null +++ b/frontend/public/stickers/animals/bear_hug.svg @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/animals/bunny_cheer.svg b/frontend/public/stickers/animals/bunny_cheer.svg new file mode 100644 index 00000000..8faecdfe --- /dev/null +++ b/frontend/public/stickers/animals/bunny_cheer.svg @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/animals/cat_heart.svg b/frontend/public/stickers/animals/cat_heart.svg new file mode 100644 index 00000000..efd03bca --- /dev/null +++ b/frontend/public/stickers/animals/cat_heart.svg @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/animals/cat_laptop.svg b/frontend/public/stickers/animals/cat_laptop.svg new file mode 100644 index 00000000..05d192fa --- /dev/null +++ b/frontend/public/stickers/animals/cat_laptop.svg @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/animals/dog_happy.svg b/frontend/public/stickers/animals/dog_happy.svg new file mode 100644 index 00000000..051d10bf --- /dev/null +++ b/frontend/public/stickers/animals/dog_happy.svg @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/animals/fox_sleeping.svg b/frontend/public/stickers/animals/fox_sleeping.svg new file mode 100644 index 00000000..18dc29bf --- /dev/null +++ b/frontend/public/stickers/animals/fox_sleeping.svg @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/animals/panda_bamboo.svg b/frontend/public/stickers/animals/panda_bamboo.svg new file mode 100644 index 00000000..3c931ac3 --- /dev/null +++ b/frontend/public/stickers/animals/panda_bamboo.svg @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/animals/penguin_waddle.svg b/frontend/public/stickers/animals/penguin_waddle.svg new file mode 100644 index 00000000..5286e74a --- /dev/null +++ b/frontend/public/stickers/animals/penguin_waddle.svg @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/anime/chibi_blush.svg b/frontend/public/stickers/anime/chibi_blush.svg new file mode 100644 index 00000000..60394f00 --- /dev/null +++ b/frontend/public/stickers/anime/chibi_blush.svg @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/anime/chibi_coffee.svg b/frontend/public/stickers/anime/chibi_coffee.svg new file mode 100644 index 00000000..cf7f8d44 --- /dev/null +++ b/frontend/public/stickers/anime/chibi_coffee.svg @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/anime/chibi_gaming.svg b/frontend/public/stickers/anime/chibi_gaming.svg new file mode 100644 index 00000000..3d1e75f6 --- /dev/null +++ b/frontend/public/stickers/anime/chibi_gaming.svg @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/anime/chibi_peace.svg b/frontend/public/stickers/anime/chibi_peace.svg new file mode 100644 index 00000000..594e78a2 --- /dev/null +++ b/frontend/public/stickers/anime/chibi_peace.svg @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/anime/chibi_rage.svg b/frontend/public/stickers/anime/chibi_rage.svg new file mode 100644 index 00000000..b5cb9efe --- /dev/null +++ b/frontend/public/stickers/anime/chibi_rage.svg @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/anime/chibi_sleepy.svg b/frontend/public/stickers/anime/chibi_sleepy.svg new file mode 100644 index 00000000..4f7fe8c2 --- /dev/null +++ b/frontend/public/stickers/anime/chibi_sleepy.svg @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/anime/chibi_sparkle.svg b/frontend/public/stickers/anime/chibi_sparkle.svg new file mode 100644 index 00000000..f0ce2920 --- /dev/null +++ b/frontend/public/stickers/anime/chibi_sparkle.svg @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/anime/chibi_sweat.svg b/frontend/public/stickers/anime/chibi_sweat.svg new file mode 100644 index 00000000..bd37848c --- /dev/null +++ b/frontend/public/stickers/anime/chibi_sweat.svg @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/memes/bruh.svg b/frontend/public/stickers/memes/bruh.svg new file mode 100644 index 00000000..18c6a879 --- /dev/null +++ b/frontend/public/stickers/memes/bruh.svg @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/memes/doge_wow.svg b/frontend/public/stickers/memes/doge_wow.svg new file mode 100644 index 00000000..56733dfc --- /dev/null +++ b/frontend/public/stickers/memes/doge_wow.svg @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/memes/gg_wp.svg b/frontend/public/stickers/memes/gg_wp.svg new file mode 100644 index 00000000..3c1f6c86 --- /dev/null +++ b/frontend/public/stickers/memes/gg_wp.svg @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/memes/pepe_happy.svg b/frontend/public/stickers/memes/pepe_happy.svg new file mode 100644 index 00000000..da269f08 --- /dev/null +++ b/frontend/public/stickers/memes/pepe_happy.svg @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/memes/pepe_hype.svg b/frontend/public/stickers/memes/pepe_hype.svg new file mode 100644 index 00000000..22006d62 --- /dev/null +++ b/frontend/public/stickers/memes/pepe_hype.svg @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/memes/pepe_sad.svg b/frontend/public/stickers/memes/pepe_sad.svg new file mode 100644 index 00000000..56e3492e --- /dev/null +++ b/frontend/public/stickers/memes/pepe_sad.svg @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/memes/pepe_smart.svg b/frontend/public/stickers/memes/pepe_smart.svg new file mode 100644 index 00000000..5d8bbb0f --- /dev/null +++ b/frontend/public/stickers/memes/pepe_smart.svg @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/memes/popcat.svg b/frontend/public/stickers/memes/popcat.svg new file mode 100644 index 00000000..79f243fa --- /dev/null +++ b/frontend/public/stickers/memes/popcat.svg @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/memes/score_100.svg b/frontend/public/stickers/memes/score_100.svg new file mode 100644 index 00000000..09851d8c --- /dev/null +++ b/frontend/public/stickers/memes/score_100.svg @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/memes/stonks.svg b/frontend/public/stickers/memes/stonks.svg new file mode 100644 index 00000000..aa37df83 --- /dev/null +++ b/frontend/public/stickers/memes/stonks.svg @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/reactions/angel.svg b/frontend/public/stickers/reactions/angel.svg new file mode 100644 index 00000000..8aeff8cc --- /dev/null +++ b/frontend/public/stickers/reactions/angel.svg @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/reactions/angry.svg b/frontend/public/stickers/reactions/angry.svg new file mode 100644 index 00000000..094b6477 --- /dev/null +++ b/frontend/public/stickers/reactions/angry.svg @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/reactions/cool.svg b/frontend/public/stickers/reactions/cool.svg new file mode 100644 index 00000000..ab6a1932 --- /dev/null +++ b/frontend/public/stickers/reactions/cool.svg @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/reactions/crying.svg b/frontend/public/stickers/reactions/crying.svg new file mode 100644 index 00000000..998a263d --- /dev/null +++ b/frontend/public/stickers/reactions/crying.svg @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/reactions/facepalm.svg b/frontend/public/stickers/reactions/facepalm.svg new file mode 100644 index 00000000..58fedb05 --- /dev/null +++ b/frontend/public/stickers/reactions/facepalm.svg @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/reactions/fire.svg b/frontend/public/stickers/reactions/fire.svg new file mode 100644 index 00000000..23326569 --- /dev/null +++ b/frontend/public/stickers/reactions/fire.svg @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/reactions/heart_eyes.svg b/frontend/public/stickers/reactions/heart_eyes.svg new file mode 100644 index 00000000..c28134a7 --- /dev/null +++ b/frontend/public/stickers/reactions/heart_eyes.svg @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/reactions/laughing.svg b/frontend/public/stickers/reactions/laughing.svg new file mode 100644 index 00000000..451afbb1 --- /dev/null +++ b/frontend/public/stickers/reactions/laughing.svg @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/reactions/mindblown.svg b/frontend/public/stickers/reactions/mindblown.svg new file mode 100644 index 00000000..b6d54dd9 --- /dev/null +++ b/frontend/public/stickers/reactions/mindblown.svg @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/reactions/party.svg b/frontend/public/stickers/reactions/party.svg new file mode 100644 index 00000000..a547b470 --- /dev/null +++ b/frontend/public/stickers/reactions/party.svg @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/reactions/shocked.svg b/frontend/public/stickers/reactions/shocked.svg new file mode 100644 index 00000000..a4f0086b --- /dev/null +++ b/frontend/public/stickers/reactions/shocked.svg @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/reactions/thinking.svg b/frontend/public/stickers/reactions/thinking.svg new file mode 100644 index 00000000..e360c30f --- /dev/null +++ b/frontend/public/stickers/reactions/thinking.svg @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/vibes/clapping.svg b/frontend/public/stickers/vibes/clapping.svg new file mode 100644 index 00000000..d7aaf1fc --- /dev/null +++ b/frontend/public/stickers/vibes/clapping.svg @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/vibes/coffee_mug.svg b/frontend/public/stickers/vibes/coffee_mug.svg new file mode 100644 index 00000000..691507c9 --- /dev/null +++ b/frontend/public/stickers/vibes/coffee_mug.svg @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/vibes/heart_hands.svg b/frontend/public/stickers/vibes/heart_hands.svg new file mode 100644 index 00000000..98bbbb6d --- /dev/null +++ b/frontend/public/stickers/vibes/heart_hands.svg @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/vibes/high_five.svg b/frontend/public/stickers/vibes/high_five.svg new file mode 100644 index 00000000..3ac6171e --- /dev/null +++ b/frontend/public/stickers/vibes/high_five.svg @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/vibes/peace_out.svg b/frontend/public/stickers/vibes/peace_out.svg new file mode 100644 index 00000000..401269ad --- /dev/null +++ b/frontend/public/stickers/vibes/peace_out.svg @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/vibes/rocket_blast.svg b/frontend/public/stickers/vibes/rocket_blast.svg new file mode 100644 index 00000000..5e6fa36e --- /dev/null +++ b/frontend/public/stickers/vibes/rocket_blast.svg @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/vibes/sparkle_star.svg b/frontend/public/stickers/vibes/sparkle_star.svg new file mode 100644 index 00000000..0ef415d2 --- /dev/null +++ b/frontend/public/stickers/vibes/sparkle_star.svg @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/frontend/public/stickers/vibes/thumbs_up.svg b/frontend/public/stickers/vibes/thumbs_up.svg new file mode 100644 index 00000000..1cc9a74a --- /dev/null +++ b/frontend/public/stickers/vibes/thumbs_up.svg @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/frontend/src/components/MessageBubble.jsx b/frontend/src/components/MessageBubble.jsx index cc034563..7e03d8c0 100644 --- a/frontend/src/components/MessageBubble.jsx +++ b/frontend/src/components/MessageBubble.jsx @@ -52,6 +52,14 @@ const MessageBubble = ({ message, sender, isMe, chatId }) => { const canDeleteForEveryone = isMe && !message.deletedForEveryone; const isAI = sender?.isAI; + const isStickerOnly = + !message.text && + !message.image && + !message.audio && + !message.file?.url && + !message.replyTo && + message.sticker; + const highlightedText = useMemo(() => { if (!searchQuery || !message.text) return message.text; const regex = new RegExp(`(${searchQuery})`, "ig"); @@ -352,7 +360,19 @@ const MessageBubble = ({ message, sender, isMe, chatId }) => { )} -