mojmajstor/convex/chats.ts
echo c85ea09d4b feat: Phase 4 - customer posts feed, create, detail, respond
- Add create/close post mutations with auth & ownership verification
- Add getOrCreate chat mutation for handyman response flow
- PostCard component: title, description preview, category badge,
  location, budget, status badge (open=green, closed=red)
- Post detail screen: full description, category, location, budget,
  status, time-ago. Owner: close button. Handyman: respond button
  creates/opens chat with customer
- Create post screen: title, description, category picker, location,
  budget, auth-gated with redirect
- Posts feed: open/all filter tabs, new-post button for customers

All UI text in Macedonian. TypeScript clean, Convex functions deployed.
2026-05-29 18:31:08 +02:00

42 lines
1.2 KiB
TypeScript

import { query, mutation } from "./_generated/server";
import { v } from "convex/values";
export const listByUser = query({
args: { userId: v.id("users") },
handler: async (ctx, args) => {
const allChats = await ctx.db.query("chats").order("desc").collect();
return allChats.filter((chat) => chat.participantIds.includes(args.userId));
},
});
export const getOrCreate = mutation({
args: {
token: v.string(),
partnerId: v.id("users"),
},
handler: async (ctx, args) => {
const session = await ctx.db
.query("sessions")
.withIndex("by_token", (q) => q.eq("token", args.token))
.first();
if (!session) throw new Error("Неавторизиран");
const allChats = await ctx.db.query("chats").collect();
const existing = allChats.find(
(c) =>
c.participantIds.includes(session.userId) &&
c.participantIds.includes(args.partnerId) &&
c.participantIds.length === 2
);
if (existing) return existing._id;
const chatId = await ctx.db.insert("chats", {
participantIds: [session.userId, args.partnerId],
lastMessageAt: Date.now(),
createdBy: session.userId,
});
return chatId;
},
});