refactor: improve news and email handling, style, folder structure (#16)
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export function ApiResponse(status: number, message: string) {
|
||||
const response = new NextResponse(message, { status });
|
||||
response.headers.set('Access-Control-Allow-Origin', process.env.HOME_URL!);
|
||||
export function ApiResponse(status: number, message: unknown) {
|
||||
const stringMessage = JSON.stringify(message);
|
||||
|
||||
return response;
|
||||
return new NextResponse(stringMessage, { status });
|
||||
}
|
||||
|
||||
13
utils/sayings.ts
Normal file
13
utils/sayings.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export const sayings = [
|
||||
'hot off the press',
|
||||
'straight from the oven',
|
||||
"straight from the horse's mouth",
|
||||
'brand spanking new',
|
||||
'fresh as a daisy',
|
||||
'straight out of the box',
|
||||
'straight off the assembly line',
|
||||
'hot out of the kitchen',
|
||||
'just minted',
|
||||
'freshly brewed',
|
||||
'just off the production line'
|
||||
];
|
||||
@@ -1,43 +1,61 @@
|
||||
import { Resend } from 'resend';
|
||||
|
||||
type EmailTemplate = {
|
||||
interface EmailTemplate {
|
||||
subject: string;
|
||||
template: JSX.Element;
|
||||
};
|
||||
}
|
||||
|
||||
export async function sender(
|
||||
to: string[],
|
||||
recipients: string[],
|
||||
{ subject, template }: EmailTemplate
|
||||
) {
|
||||
if (recipients.length === 0) {
|
||||
console.info(`${subject} email skipped for having zero recipients`);
|
||||
return true;
|
||||
}
|
||||
|
||||
const resend = new Resend(process.env.RESEND_KEY);
|
||||
|
||||
try {
|
||||
const { error } = await resend.batch.send(
|
||||
to.map(t => {
|
||||
return {
|
||||
from: process.env.RESEND_FROM!,
|
||||
to: t,
|
||||
subject,
|
||||
react: template,
|
||||
headers: {
|
||||
'List-Unsubscribe': `<${process.env.HOME_URL}/unsubscribe>`
|
||||
}
|
||||
};
|
||||
})
|
||||
);
|
||||
let response;
|
||||
|
||||
if (recipients.length == 1) {
|
||||
response = await resend.emails.send({
|
||||
from: process.env.RESEND_FROM!,
|
||||
to: recipients[0],
|
||||
subject,
|
||||
react: template,
|
||||
headers: {
|
||||
'List-Unsubscribe': `<${process.env.HOME_URL}/unsubscribe>`
|
||||
}
|
||||
});
|
||||
} else {
|
||||
response = await resend.batch.send(
|
||||
recipients.map(recipient => {
|
||||
return {
|
||||
from: process.env.RESEND_FROM!,
|
||||
to: recipient,
|
||||
subject,
|
||||
react: template,
|
||||
headers: {
|
||||
'List-Unsubscribe': `<${process.env.HOME_URL}/unsubscribe>`
|
||||
}
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const { error } = response;
|
||||
|
||||
if (error) {
|
||||
console.log(error);
|
||||
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
console.info(`${subject} email sent to ${recipients.length} recipients`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('Email sent', subject, to.length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
6
utils/statusCodes.ts
Normal file
6
utils/statusCodes.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export const STATUS_OK = 200;
|
||||
export const STATUS_BAD_REQUEST = 400;
|
||||
export const BAD_REQUEST = 'Bad request';
|
||||
export const STATUS_INTERNAL_SERVER_ERROR = 500;
|
||||
export const INTERNAL_SERVER_ERROR = 'Internal server error';
|
||||
export const STATUS_UNAUTHORIZED = 401;
|
||||
@@ -1,3 +1,5 @@
|
||||
export const topNews = 'https://hacker-news.firebaseio.com/v0/topstories.json';
|
||||
export const singleNews = (id: number) =>
|
||||
`https://hacker-news.firebaseio.com/v0/item/${id}.json`;
|
||||
|
||||
export function singleNews(id: number) {
|
||||
return `https://hacker-news.firebaseio.com/v0/item/${id}.json`;
|
||||
}
|
||||
|
||||
@@ -5,20 +5,24 @@ export const ResponseSchema = z.object({
|
||||
message: z.string()
|
||||
});
|
||||
|
||||
export type ResponseType = z.infer<typeof ResponseSchema>;
|
||||
|
||||
export const SubscribeFormSchema = z.object({
|
||||
email: z.string().email(),
|
||||
name: z.string().optional()
|
||||
email: z.string().email()
|
||||
});
|
||||
|
||||
export type SubscribeFormType = z.infer<typeof SubscribeFormSchema>;
|
||||
|
||||
export const ConfirmationSchema = z.object({
|
||||
code: z.string()
|
||||
});
|
||||
|
||||
export const UnsubscribeFormSchema = z.object({
|
||||
email: z.string().email(),
|
||||
name: z.string().optional()
|
||||
email: z.string().email()
|
||||
});
|
||||
|
||||
export type UnsubscribeFormType = z.infer<typeof UnsubscribeFormSchema>;
|
||||
|
||||
export const NewsDatabaseSchema = z.object({
|
||||
id: z.number(),
|
||||
title: z.string(),
|
||||
@@ -30,6 +34,8 @@ export const NewsDatabaseSchema = z.object({
|
||||
score: z.number()
|
||||
});
|
||||
|
||||
export type NewsDatabaseType = z.infer<typeof NewsDatabaseSchema>;
|
||||
|
||||
export const NewsSchema = z.object({
|
||||
id: z.number(),
|
||||
title: z.string(),
|
||||
@@ -42,10 +48,12 @@ export const NewsSchema = z.object({
|
||||
createdAt: z.date()
|
||||
});
|
||||
|
||||
export type NewsType = z.infer<typeof NewsSchema>;
|
||||
|
||||
export const NewsTileSchema = z.object({
|
||||
id: z.number(),
|
||||
title: z.string(),
|
||||
by: z.string()
|
||||
});
|
||||
|
||||
export type NewsTile = z.infer<typeof NewsTileSchema>;
|
||||
export type NewsTileType = z.infer<typeof NewsTileSchema>;
|
||||
Reference in New Issue
Block a user