diff --git a/apps/web/app/api/user/brands/route.ts b/apps/web/app/api/user/brands/route.ts index ac7b686b..1bd3e2d7 100644 --- a/apps/web/app/api/user/brands/route.ts +++ b/apps/web/app/api/user/brands/route.ts @@ -360,147 +360,38 @@ export const POST = withSession(async ({ req, session }) => { { status: 500 }, ); } - } else if (advertiserId === "5") { - interface Campaign { - CampaignId: string; - AdvertiserName: string; - CampaignUrl: string; - } - - interface ApiResponse { - "@total": string; - "@numpages": string; - "@page": string; - "@nextpageuri": string; - Campaigns: Campaign[]; - } - - try { - if (!accountId || !encryptedApiKey) { - return NextResponse.json( - { error: "Missing Impact.com credentials." }, - { status: 400 }, - ); - } - - const apiKey = decrypt(encryptedApiKey); - const baseUrl = `https://api.impact.com/Mediapartners/${accountId}/Campaigns`; - const headers = { - Accept: "application/json", - Authorization: `Basic ${Buffer.from(`${accountId}:${apiKey}`).toString("base64")}`, - }; - const params = new URLSearchParams({ - InsertionOrderStatus: "Active", - PageSize: "100", // Maximum allowed page size - }); - - let allCampaigns: Campaign[] = []; - let nextPageUri = `${baseUrl}?${params}`; - - while (nextPageUri) { - const response = await fetch(nextPageUri, { headers }); - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const data = (await response.json()) as ApiResponse; - allCampaigns = allCampaigns.concat(data.Campaigns); - - nextPageUri = data["@nextpageuri"] - ? `https://api.impact.com${data["@nextpageuri"]}` - : ""; - } - - // Process campaigns and update database - const processedBrands = await Promise.all( - allCampaigns.map(async (campaign) => { - const brandName = campaign.AdvertiserName; - const brandId = campaign.CampaignId; - const advertiserUrl = campaign.CampaignUrl; - const modifiedUrl = extractBaseUrlUpdated(advertiserUrl); - - if (modifiedUrl) { - const brand = await prisma.brand.findFirst({ - where: { - url: modifiedUrl, - advertisers: { - some: { - brandIdAtAdvertiser: brandId, - advertiserId, - }, - }, - }, - include: { - advertisers: { - where: { advertiserId: advertiserId }, - }, - userBrandRelationships: { - where: { userId: session.user.id, advertiserId }, - }, - }, - }); - - if (!brand) { - const newBrand = await prisma.brand.create({ - data: { - name: brandName, - url: modifiedUrl, - advertisers: { - create: { - brandIdAtAdvertiser: brandId, - advertiserId, - }, - }, - }, - include: { - advertisers: { - where: { advertiserId: advertiserId }, - }, - }, - }); - - const userBrandRelationship = - await prisma.userBrandRelationship.create({ - data: { - userId: session.user.id, - brandId: newBrand.id, - advertiserId, - userAdvertiserRelationId: relationship.id, - brandAdvertiserRelationId: newBrand.advertisers[0].id, - }, - }); - - return { brand: newBrand, userBrandRelationship }; - } - - if (brand) { - let userBrandRelationship = brand.userBrandRelationships[0]; - if (!userBrandRelationship) { - userBrandRelationship = - await prisma.userBrandRelationship.create({ - data: { - userId: session.user.id, - brandId: brand.id, - advertiserId, - userAdvertiserRelationId: relationship.id, - brandAdvertiserRelationId: brand.advertisers[0].id, - }, - }); - } - - return { brand, userBrandRelationship }; - } - } - return null; - }), - ); - - const validBrands = processedBrands.filter(Boolean); - return NextResponse.json(validBrands); - } catch (error) { - console.error("Error processing Impact.com advertiser:", error); - return NextResponse.json( - { error: "Internal server error" }, + // } else if (advertiserId === "5") { + // // Partnerize-specific processing + // try { + // const apiKey = decrypt(encryptedApiKey); + // const partnerizeUrl = "https://api.partnerize.com/v1/affiliate/link"; + + // const response = await fetch(partnerizeUrl, { + // method: "POST", + // headers: { + // Authorization: `Bearer ${apiKey}`, + // "Content-Type": "application/json", + // }, + // body: JSON.stringify({ + // url: processedUrl, + // campaign_id: accountId, + // }), + // }); + + // if (response.ok) { + // const data = await response.json(); + // return NextResponse.json({ affiliateUrl: data.affiliate_link_url }); + // } else { + // const errorData = await response.json(); + // return NextResponse.json( + // { error: `Partnerize API error: ${errorData.message}` }, + // { status: response.status }, + // ); + // } + // } catch (error) { + // console.error("Error processing Partnerize advertiser:", error); + // return NextResponse.json( + // { error: "Internal server error" }, { status: 500 }, ); } diff --git a/apps/web/lib/api/links.ts b/apps/web/lib/api/links.ts index cd579f66..5d148d69 100644 --- a/apps/web/lib/api/links.ts +++ b/apps/web/lib/api/links.ts @@ -692,65 +692,49 @@ export async function processLink({ console.error("Error generating affiliate link:", error); } } else if (advertiserId === "5") { - // Impact.com - - interface ImpactApiResponse { - TrackingURL: string; - // Add other fields that might be in the response - Status?: string; - Message?: string; - } - const userAdvertiserRelation = userBrandRelationship.userAdvertiserRelation; - const impactAccountId = userAdvertiserRelation.accountId || ""; - const brandId = - userBrandRelationship.brandAdvertiserRelation.brandIdAtAdvertiser; - const impactApiKey = decrypt( - userAdvertiserRelation.encryptedApiKey || "", - ); - if (!impactApiKey || !impactAccountId) { + const apiKey = decrypt(userAdvertiserRelation.encryptedApiKey || ""); + const accountId = userAdvertiserRelation.accountId || ""; + + if (!apiKey || !accountId) { return { link: payload, - error: "Missing credentials for Impact.com affiliate program.", + error: "Missing credentials for Partnerize affiliate program.", code: "unprocessable_entity", }; } - const impactUrl = `https://api.impact.com/Mediapartners/${impactAccountId}/Programs/${brandId}/TrackingLinks`; - const encodedUrl = encodeURIComponent(processedUrl); - - // Add the deep link as a query parameter - const urlWithParams = `${impactUrl}?DeepLink=${encodedUrl}`; + const partnerizeUrl = "https://api.partnerize.com/v1/affiliate/link"; const headers = { - Accept: "application/json", - // Using Basic Auth instead of Bearer token - Authorization: `Basic ${Buffer.from(`${impactAccountId}:${impactApiKey}`).toString("base64")}`, + Authorization: `Bearer ${apiKey}`, + "Content-Type": "application/json", + }; + + const data = { + url: processedUrl, + campaign_id: accountId, }; try { - const response = await fetch(urlWithParams, { - method: "POST", // Changed from POST to GET + const response = await fetch(partnerizeUrl, { + method: "POST", headers, - // Removed body since we're using GET + body: JSON.stringify(data), }); if (response.ok) { - const responseData = (await response.json()) as ImpactApiResponse; - - if (!responseData.TrackingURL) { - throw new Error("No tracking URL found in response"); - } - - clickUrl = responseData.TrackingURL; + const responseJson = await response.json(); + const affiliateUrl = responseJson.affiliate_link_url || ""; + clickUrl = affiliateUrl; } else { const errorData = await response.json(); - console.error(`Error: ${errorData}`); + console.error(`Partnerize API error: ${errorData.message}`); } } catch (error) { - console.error("Error generating Impact.com affiliate link:", error); + console.error("Error generating Partnerize affiliate link:", error); } } } diff --git a/apps/web/ui/modals/add-edit-network-modal.tsx b/apps/web/ui/modals/add-edit-network-modal.tsx index 78fd44f8..348d7502 100644 --- a/apps/web/ui/modals/add-edit-network-modal.tsx +++ b/apps/web/ui/modals/add-edit-network-modal.tsx @@ -752,6 +752,65 @@ function AddEditNetworkModal({ + ) : advertiserId === "5" ? ( // Partnerize + <> +
+
+ + + + +
+
+ handleInputChange("partialApiKey", e.target.value)} + className="border-gray-300 text-gray-900 placeholder-gray-300 focus:border-gray-500 focus:ring-gray-500 block w-full rounded-md focus:outline-none sm:text-sm" + aria-invalid="true" + /> +
+
+
+
+ + + + +
+
+ handleInputChange("accountId", e.target.value)} + className="border-gray-300 text-gray-900 placeholder-gray-300 focus:border-gray-500 focus:ring-gray-500 block w-full rounded-md focus:outline-none sm:text-sm" + aria-invalid="true" + /> +
+
+ ) : null}