Skip to content

Commit 709f9ed

Browse files
committed
SDK demo app
1 parent db2aced commit 709f9ed

17 files changed

+4543
-0
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
LOOPS_API_KEY=

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.DS_Store
2+
node_modules/
3+
.next/
4+
.env

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Loops JavaScript/TypeScript SDK
2+
3+
## Install
4+
5+
```bash
6+
npm install @loops/loops
7+
```

app/api/contacts/route.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
3+
import LoopsClient from "loops-js";
4+
5+
const loops = new LoopsClient(process.env.LOOPS_API_KEY);
6+
7+
8+
/**
9+
* Create or Update a contact
10+
*/
11+
export async function POST(request: Request) {
12+
// Properties can be sent as JSON along with the email address
13+
const res = await request.json();
14+
15+
const email = res["email"];
16+
17+
const data = await loops.createContact(email);
18+
19+
// Other options for adding properties and updating a contact
20+
// const properties = { plan: 'Pro' }
21+
// const data = await loops.createContact(email, properties)
22+
// const data = await loops.updateContact(email, properties)
23+
24+
return NextResponse.json({ data });
25+
}
26+
27+
/**
28+
* Search for a contact by email
29+
*/
30+
export async function GET(request: NextRequest) {
31+
const searchParams = request.nextUrl.searchParams;
32+
const query: string | null = searchParams.get("q");
33+
34+
if (!query) throw "No email given";
35+
36+
const data = await loops.findContact(query);
37+
38+
return NextResponse.json({ data });
39+
}
40+
41+
/**
42+
* Delete a contact
43+
*/
44+
export async function DELETE(request: NextRequest) {
45+
const searchParams = request.nextUrl.searchParams;
46+
const email: string | null = searchParams.get("email");
47+
48+
if (!email) throw "No email given";
49+
50+
const data = await loops.deleteContact({ email });
51+
52+
return NextResponse.json({ data });
53+
}

app/favicon.ico

25.3 KB
Binary file not shown.

app/globals.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;

app/layout.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import "./globals.css";
2+
import type { Metadata } from "next";
3+
import { Inter } from "next/font/google";
4+
5+
const inter = Inter({ subsets: ["latin"] });
6+
7+
export const metadata: Metadata = {
8+
title: "Loops Next.js Demo app"
9+
};
10+
11+
export default function RootLayout({
12+
children,
13+
}: {
14+
children: React.ReactNode
15+
}) {
16+
return (
17+
<html lang="en">
18+
<body className={inter.className}>{children}</body>
19+
</html>
20+
)
21+
};

app/page.tsx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"use client";
2+
3+
import { useState } from "react";
4+
5+
export default function Page() {
6+
7+
const [email, setEmail] = useState<string>("");
8+
const [results, setResults] = useState<string>("");
9+
10+
async function addOrUpdateContact() {
11+
if (email == "") return;
12+
const resp = await fetch("/api/contacts", {
13+
method: "POST",
14+
body: JSON.stringify({ email }) // extra contact properties can be sent in the JSON too
15+
});
16+
const data = await resp.json();
17+
setResults(JSON.stringify(data["data"], null, 4));
18+
}
19+
20+
async function findContact() {
21+
if (email == "") return;
22+
const params = new URLSearchParams({ q: email }).toString();
23+
const resp = await fetch(`/api/contacts?${params}`);
24+
const data = await resp.json();
25+
setResults(JSON.stringify(data["data"], null, 4));
26+
}
27+
28+
async function deleteContact() {
29+
if (email == "") return;
30+
const params = new URLSearchParams({ email }).toString();
31+
const resp = await fetch(`/api/contacts?${params}`, { method: "DELETE" });
32+
const data = await resp.json();
33+
setResults(JSON.stringify(data["data"], null, 4));
34+
}
35+
36+
return (
37+
<main className="p-8 max-w-lg">
38+
<h1 className="font-bold text-2xl">Loops SDK Tester</h1>
39+
<p className="my-4">
40+
<input
41+
type="email" name="email" placeholder="Email address"
42+
className="p-2 w-full border rounded-md"
43+
onChange={(e) => setEmail(e.target.value)}
44+
/>
45+
</p>
46+
<p className="my-4">
47+
<button onClick={addOrUpdateContact} className="px-4 py-2 rounded-md bg-green-600 text-white">Add contact</button> &nbsp;
48+
<button onClick={findContact} className="px-4 py-2 rounded-md bg-blue-600 text-white">Find contact</button> &nbsp;
49+
<button onClick={deleteContact} className="px-4 py-2 rounded-md bg-red-600 text-white">Delete contact</button>
50+
</p>
51+
<pre className="mt-8 w-full overflow-scroll">{results}</pre>
52+
</main>
53+
)
54+
}

next-env.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// <reference types="next" />
2+
/// <reference types="next/image-types/global" />
3+
4+
// NOTE: This file should not be edited
5+
// see https://nextjs.org/docs/basic-features/typescript for more information.

next.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/** @type {import('next').NextConfig} */
2+
const nextConfig = {}
3+
4+
module.exports = nextConfig

0 commit comments

Comments
 (0)