From 7b3d1ba23ae2b433235f8bd165a4224d6e67ad77 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Mon, 9 Jun 2025 11:04:36 -0700 Subject: [PATCH] Include the user who shared the task on the share landing page (#87) * Include the user who shared the task on the share landing page * Add sharedAt --- src/actions/taskSharing.ts | 35 ++++++++++++++----- .../(authenticated)/share/[token]/page.tsx | 9 +++-- .../task-sharing/SharedTaskView.tsx | 19 +++++++--- src/types/task-sharing.ts | 6 ++++ 4 files changed, 55 insertions(+), 14 deletions(-) diff --git a/src/actions/taskSharing.ts b/src/actions/taskSharing.ts index 968770e093..1eadd75a16 100644 --- a/src/actions/taskSharing.ts +++ b/src/actions/taskSharing.ts @@ -9,9 +9,10 @@ import { createTaskShareSchema, shareIdSchema, } from '@/types'; +import type { SharedByUser } from '@/types/task-sharing'; import type { Message } from '@/types/analytics'; import { type TaskShare, AuditLogTargetType } from '@/db'; -import { client as db, taskShares } from '@/db/server'; +import { client as db, taskShares, users } from '@/db/server'; import { handleError, isAuthSuccess, generateShareToken } from '@/lib/server'; import { isValidShareToken, @@ -199,9 +200,12 @@ export async function createTaskShare( /** * Get task data by share token (for viewing shared tasks) */ -export async function getTaskByShareToken( - token: string, -): Promise<{ task: TaskWithUser; messages: Message[] } | null> { +export async function getTaskByShareToken(token: string): Promise<{ + task: TaskWithUser; + messages: Message[]; + sharedBy: SharedByUser; + sharedAt: Date; +} | null> { try { const { userId, orgId } = await auth(); @@ -213,16 +217,26 @@ export async function getTaskByShareToken( return null; } - const [share] = await db - .select() + const [shareWithUser] = await db + .select({ + share: taskShares, + sharedByUser: { + id: users.id, + name: users.name, + email: users.email, + }, + }) .from(taskShares) + .innerJoin(users, eq(taskShares.createdByUserId, users.id)) .where(and(eq(taskShares.shareToken, token), eq(taskShares.orgId, orgId))) .limit(1); - if (!share) { + if (!shareWithUser) { return null; } + const { share, sharedByUser } = shareWithUser; + if (isShareExpired(share.expiresAt)) { return null; } @@ -240,7 +254,12 @@ export async function getTaskByShareToken( const messages = await getMessages(share.taskId); - return { task, messages }; + return { + task, + messages, + sharedBy: sharedByUser, + sharedAt: share.createdAt, + }; } catch (error) { console.error( 'Error getting task by share token:', diff --git a/src/app/(authenticated)/share/[token]/page.tsx b/src/app/(authenticated)/share/[token]/page.tsx index ba5f43e658..a36f9c49c5 100644 --- a/src/app/(authenticated)/share/[token]/page.tsx +++ b/src/app/(authenticated)/share/[token]/page.tsx @@ -26,7 +26,7 @@ export default async function SharedTaskPage({ params }: SharedTaskPageProps) { notFound(); } - const { task, messages } = result; + const { task, messages, sharedBy, sharedAt } = result; return (
@@ -35,7 +35,12 @@ export default async function SharedTaskPage({ params }: SharedTaskPageProps) { Shared Task
- + ); } catch (error) { diff --git a/src/components/task-sharing/SharedTaskView.tsx b/src/components/task-sharing/SharedTaskView.tsx index cc9aa34b1d..d785cc0818 100644 --- a/src/components/task-sharing/SharedTaskView.tsx +++ b/src/components/task-sharing/SharedTaskView.tsx @@ -1,5 +1,6 @@ import type { TaskWithUser } from '@/actions/analytics'; import type { Message } from '@/types/analytics'; +import type { SharedByUser } from '@/types/task-sharing'; import { formatCurrency, formatNumber } from '@/lib/formatters'; import { generateFallbackTitle } from '@/lib/task-utils'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui'; @@ -9,9 +10,16 @@ import { Messages } from '@/app/(authenticated)/usage/Messages'; type SharedTaskViewProps = { task: TaskWithUser; messages: Message[]; + sharedBy: SharedByUser; + sharedAt: Date; }; -export const SharedTaskView = ({ task, messages }: SharedTaskViewProps) => { +export const SharedTaskView = ({ + task, + messages, + sharedBy, + sharedAt, +}: SharedTaskViewProps) => { const taskTitle = task.title || generateFallbackTitle(task); return ( @@ -23,8 +31,7 @@ export const SharedTaskView = ({ task, messages }: SharedTaskViewProps) => {
{taskTitle}

- Shared by {task.user.name} •{' '} - {new Date(task.timestamp * 1000).toLocaleDateString()} + Shared by {sharedBy.name} • {sharedAt.toLocaleDateString()}

@@ -36,7 +43,11 @@ export const SharedTaskView = ({ task, messages }: SharedTaskViewProps) => {
-
+
+
+

Developer

+

{task.user.name}

+

Model

{task.model}

diff --git a/src/types/task-sharing.ts b/src/types/task-sharing.ts index 6cd47cab8f..11aa76132b 100644 --- a/src/types/task-sharing.ts +++ b/src/types/task-sharing.ts @@ -10,3 +10,9 @@ export type CreateTaskShareRequest = z.infer; export const shareIdSchema = z.string().uuid('Invalid share ID format'); export type ShareId = z.infer; + +export type SharedByUser = { + id: string; + name: string; + email: string; +};