Skip to content

Commit

Permalink
fetching data tested
Browse files Browse the repository at this point in the history
  • Loading branch information
lohpaul9 committed Feb 5, 2024
1 parent eb386af commit 8802099
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
AIRTABLE_TEST_API_KEY=your_api_key
AIRTABLE_TEST_BASE_ID=starts_with_app
AIRTABLE_TEST_TABLE_ID=your_table_id
21 changes: 21 additions & 0 deletions src/app/api/crm_example/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { AirtableCRMProvider, AirtableCRMTable } from "../../../lib/crm_data/airtable";

const AIRTABLE_TEST_API_KEY = process.env.AIRTABLE_TEST_API_KEY || "";
const AIRTABLE_TEST_BASE_ID = process.env.AIRTABLE_TEST_BASE_ID || "";
const AIRTABLE_TEST_TABLE_ID = process.env.AIRTABLE_TEST_TABLE_ID || "";


export async function GET(request: Request) {
const provider = new AirtableCRMProvider(AIRTABLE_TEST_BASE_ID, AIRTABLE_TEST_API_KEY);

const table = provider.getTable(AIRTABLE_TEST_TABLE_ID);

const newObj = { "id": "recXIkBPF628WMnSA", "Address": "My House Changed!", "Phone": "(123) 456-7890", "RECORD_ID": "recXIkBPF628WMnSA" };

const clientInfo = await table.storeClientByPhone("1234567890", newObj);
return new Response(JSON.stringify("Success!"), {
headers: {
"content-type": "application/json",
},
});
}
124 changes: 124 additions & 0 deletions src/lib/crm_data/airtable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { CRMEntry, CRMTable, ConnieCRMProvider } from "./types"

const AIRTABLE_API_BASE: string = process.env.AIRTABLE_API_BASE || 'https://api.airtable.com/v0';

export class AirtableCRMTable implements CRMTable {
constructor(private baseId: string, private tableId: string, private token: string) { }

/**
* Makes a call to the Airtable API.
* @param url - The URL to make the API call to.
* @param headers - The headers to include in the API call.
* @param method - The HTTP method to use for the API call. Defaults to "GET".
* @param body - The request body to include in the API call.
* @returns A Promise that resolves to the API response.
*/
makeAirtableCall(url: string, headers: Record<string, string>, method?: string, body?: any): Promise<Response> {
console.log("Json obj:", JSON.stringify(body));
return fetch(url, {
method: method || "GET",
headers: {
...headers,
Authorization: `Bearer ${this.token}`
},
body: JSON.stringify(body)
});
}

async parseSingleCrmEntry(response: Response, mayHaveMultipleRecords: boolean): Promise<CRMEntry | null> {
const data = await response.json();
let record;
if (mayHaveMultipleRecords) {
// check if records was empty
if (data.records.length === 0) {
return null;
}

// return the first record by converting it into a CRMEntry
// We take its id and fields and return it as a CRMEntry
record = data.records[0];
} else {
record = data;
}
return {
id: record.id,
...record.fields
};
}


async getRowById(recordId: string): Promise<CRMEntry | null> {
const airtableUrl = `${AIRTABLE_API_BASE}/${this.baseId}/${this.tableId}/${recordId}`;

const response = await this.makeAirtableCall(airtableUrl, {}, "GET");

// check for error code
if (response.status !== 200) {
throw new Error(`Error fetching data from airtable: ${response.status} - ${response.statusText}`);
}

return this.parseSingleCrmEntry(response, false);
}

/**
* Retrieves a client from Airtable based on their phone number.
* @param phoneNumber - The phone number of the client.
* @returns A Promise that resolves to a CRMEntry object representing the client, or null if not found.
* @see {@link https://airtable.com/developers/web/api/list-records}
*/
async getClientByPhone(phoneNumber: string): Promise<CRMEntry | null> {
// do a fetch from airtable API
const filterFormula: string = `Phone=\"${AirtableCRMTable.formatPhoneNumber(phoneNumber)}\"`;
const encodedFormula: string = encodeURIComponent(filterFormula);
const airtableUrl: string = `${AIRTABLE_API_BASE}/${this.baseId}/${this.tableId}?filterByFormula=${encodedFormula}`;
// console.log(airtableUrl);

const response = await this.makeAirtableCall(airtableUrl, {}, "GET");
return this.parseSingleCrmEntry(response, true);

}

async storeClientByPhone(phoneNumber: string, client: CRMEntry): Promise<void> {
// TODO: Implement this method
// if (client.id) {
// const airtableUrl = `${AIRTABLE_API_BASE}/${this.baseId}/${this.tableId}/${client.id}`;

// // remove id and RECORD_ID if they are in the CRM entry
// delete client.id;
// delete client.RECORD_ID;


// const fields = { ...client };
// const dataObj = { fields };
// const response = await this.makeAirtableCall(airtableUrl, {}, "PATCH", dataObj);
// if (response.status !== 200) {
// throw new Error(`Error updating data in airtable: ${response.status} - ${response.statusText}`);
// }
// } else {
// // not implemented yet
// throw new Error("Not yet implemented - storing new object");
// }
throw new Error("Not yet implemented");
}

// helper converts a string number into this format (123) 456-7890
static formatPhoneNumber(phoneNumber: string): string {
// first remove all non-numeric characters
phoneNumber = phoneNumber.replace(/\D/g, '');
return `(${phoneNumber.slice(0, 3)}) ${phoneNumber.slice(3, 6)}-${phoneNumber.slice(6)}`;
}
}

export class AirtableCRMProvider implements ConnieCRMProvider {
constructor(private baseId: string, private token: string) { }
getDefaultTable(): CRMTable {
return new AirtableCRMTable(this.baseId, "clients", this.token);
}

getTable(table_id: string): CRMTable {
return new AirtableCRMTable(this.baseId, table_id, this.token);
}
}



13 changes: 13 additions & 0 deletions src/lib/crm_data/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Data type that encapsulates
export type CRMEntry = { [key: string]: string };

export interface CRMTable {
getRowById(id: string): Promise<CRMEntry | null>;
getClientByPhone(phoneNumber: string): Promise<CRMEntry | null>;
storeClientByPhone(phoneNumber: string, client: CRMEntry): Promise<void>;
}

export interface ConnieCRMProvider {
getTable(id: string): CRMTable;
getDefaultTable(): CRMTable;
}

0 comments on commit 8802099

Please sign in to comment.