diff --git a/src/client/components/DataSource.tsx b/src/client/components/DataSource.tsx index 41a7243..9aa3dd2 100644 --- a/src/client/components/DataSource.tsx +++ b/src/client/components/DataSource.tsx @@ -88,9 +88,8 @@ const getPurchaseHistory = async (brandConfig: BrandConfig) => { image_urls: item.image_urls as string[], })); - // Get detailed data for wayfair and office depot brands + // Get detailed data for office depot brand only if ( - brandConfig.brand_name.toLowerCase() === 'wayfair' && brandConfig.brand_name.toLowerCase() === 'office depot' && purchaseHistory.length > 0 ) { diff --git a/src/client/config/wayfair.json b/src/client/config/wayfair.json index 0f95a44..508be90 100644 --- a/src/client/config/wayfair.json +++ b/src/client/config/wayfair.json @@ -2,6 +2,8 @@ "brand_id": "wayfair", "brand_name": "Wayfair", "logo_url": "https://upload.wikimedia.org/wikipedia/commons/0/0a/Wayfair_logo_with_tagline.png", + "is_mandatory": false, + "is_dpage": true, "dataTransform": { "dataPath": "data.orderProductPagesByCustomer.nodes", "fieldMappings": [ @@ -17,7 +19,7 @@ }, { "outputKey": "order_date", - "sourcePath": "order_date", + "sourcePath": "order_date_and_store", "defaultValue": "N/A", "transform": "date" }, @@ -29,14 +31,16 @@ "defaultValue": "$0.00" }, { - "outputKey": "product_name", - "sourcePath": "product_name", - "defaultValue": "Unknown Product" + "outputKey": "product_names", + "sourcePath": "product_names", + "defaultValue": "Unknown Product", + "convertToArray": true }, { - "outputKey": "image_url", - "sourcePath": "image_url", - "defaultValue": "" + "outputKey": "image_urls", + "sourcePath": "image_urls", + "defaultValue": "", + "convertToArray": true } ] }, diff --git a/src/client/modules/DataTransformSchema.ts b/src/client/modules/DataTransformSchema.ts index ec6b86a..5a5c779 100644 --- a/src/client/modules/DataTransformSchema.ts +++ b/src/client/modules/DataTransformSchema.ts @@ -69,6 +69,16 @@ function getNestedValue(obj: any, path: string): any { }, obj); } +export function parseOrderDate(orderDateStr: string) { + // Match pattern like "Ordered On: June 4, 2025Wayfair Order #4325262636" + const orderMatch = orderDateStr.match(/Ordered On:\s*(\w+ \d+, \d+)/i); + if (orderMatch) { + return new Date(orderMatch[1]); + } + + return null; +} + function parseReturnDate(returnDateStr: string) { const match = returnDateStr.match(/closed on (\w+ \d+, \d+)/); if (match) { @@ -126,12 +136,36 @@ function applyTransform( if (Array.isArray(value)) { return value.map((v) => { if (typeof v === 'string') { - return parseReturnDate(v); + const orderDateParsed = parseOrderDate(v); + if (orderDateParsed) { + return orderDateParsed; + } + + const returnDateParsed = parseReturnDate(v); + if (returnDateParsed) { + return returnDateParsed; + } + + return new Date(v); } return v; }); } + if (typeof value === 'string') { + const orderDateParsed = parseOrderDate(value); + if (orderDateParsed) { + return orderDateParsed; + } + + const returnDateParsed = parseReturnDate(value); + if (returnDateParsed) { + return returnDateParsed; + } + + return new Date(value); + } + if (typeof value === 'object' && value.displayDate) { return String(value.displayDate); } @@ -169,7 +203,7 @@ export function transformData( // Handle both pre-processed arrays and raw objects that need path extraction. // Some data sources (like MCP calls) return pre-processed arrays, // while others (like Wayfair GraphQL) require extracting data using schema.dataPath - var dataArray: Array; + let dataArray: Array; if (Array.isArray(rawData)) { dataArray = rawData; } else { diff --git a/src/server/handlers/mcp-handler.ts b/src/server/handlers/mcp-handler.ts index 60a69fa..c02b87b 100644 --- a/src/server/handlers/mcp-handler.ts +++ b/src/server/handlers/mcp-handler.ts @@ -4,6 +4,7 @@ import { mcpClientManager } from '../mcp-client.js'; import { settings } from '../config.js'; import { geolocationService } from '../services/geolocation-service.js'; import { analytics } from '../services/analytics-service.js'; +import { finalizeSignin } from '../services/mcp-service.js'; const tools: Record = { amazon: ['amazon_dpage_get_purchase_history'], @@ -11,7 +12,7 @@ const tools: Record = { 'officedepot_get_order_history', 'officedepot_get_order_history_details', ], - wayfair: ['wayfair_get_order_history', 'wayfair_get_order_history_details'], + wayfair: ['wayfair_dpage_get_order_history'], goodreads: ['goodreads_get_book_list'], }; @@ -37,7 +38,7 @@ const McpResponse = z.object({ books: z.array(z.record(z.unknown())).optional(), // amazon response purchases: z.array(z.record(z.unknown())).optional(), - // wayfair and officedepot response + // officedepot response purchase_history: z.array(z.record(z.unknown())).optional(), purchase_history_details: z.array(z.record(z.unknown())).optional(), }); @@ -279,6 +280,15 @@ export const handleDpageSigninCheck = async (req: Request, res: Response) => { }); } + if (isAuthCompleted) { + finalizeSignin({ + sessionId: req.sessionID, + clientIp, + brandId, + signinId: linkId, + }); + } + res.json({ auth_completed: isAuthCompleted, link_id: linkId, diff --git a/src/server/mcp-client.ts b/src/server/mcp-client.ts index e6ccb09..fc596d6 100644 --- a/src/server/mcp-client.ts +++ b/src/server/mcp-client.ts @@ -11,6 +11,7 @@ import { geolocationService } from './services/geolocation-service.js'; const MCP_URL_PATHS: Record = { goodreads: 'mcp-books', amazon: 'mcp-shopping', + wayfair: 'mcp-shopping', }; class MCPClient { private client: Client; diff --git a/src/server/routes/api-routes.ts b/src/server/routes/api-routes.ts index 0fd1da0..fa7ec52 100644 --- a/src/server/routes/api-routes.ts +++ b/src/server/routes/api-routes.ts @@ -19,7 +19,7 @@ router.get('/dpage-signin-check/:brandId/:linkId', handleDpageSigninCheck); // Get purchase history router.get('/purchase-history/:brandId', handlePurchaseHistory); -// Get purchase history details (wayfair and officedepot) +// Get purchase history details (officedepot only) router.get( '/purchase-history-details/:brandId/:orderId', handlePurchaseHistoryDetails diff --git a/src/server/services/mcp-service.ts b/src/server/services/mcp-service.ts new file mode 100644 index 0000000..6ec49f2 --- /dev/null +++ b/src/server/services/mcp-service.ts @@ -0,0 +1,24 @@ +import { mcpClientManager } from '../mcp-client.js'; + +export async function finalizeSignin({ + sessionId, + clientIp, + brandId, + signinId, +}: { + sessionId: string; + clientIp: string; + brandId: string; + signinId: string; +}) { + const mcpClient = await mcpClientManager.get({ + sessionId, + clientIp, + brandId, + }); + + await mcpClient.callTool({ + name: 'finalize_signin', + arguments: { signin_id: signinId }, + }); +}