chore: some refactor and cleaning
This commit is contained in:
@@ -9,13 +9,12 @@ import {
|
||||
} from '@utils/statusCodes';
|
||||
import { ConfirmationSchema, ResponseType } from '@utils/validationSchemas';
|
||||
import { NextRequest } from 'next/server';
|
||||
import { Resend } from 'resend';
|
||||
|
||||
export const dynamic = 'force-dynamic'; // defaults to force-static
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
if (!process.env.RESEND_KEY || !process.env.RESEND_AUDIENCE) {
|
||||
if (!process.env.RESEND_KEY) {
|
||||
throw new Error('Resend variables not set');
|
||||
}
|
||||
const body = await request.json();
|
||||
@@ -31,14 +30,6 @@ export async function POST(request: NextRequest) {
|
||||
});
|
||||
|
||||
if (user) {
|
||||
const resend = new Resend(process.env.RESEND_KEY);
|
||||
|
||||
await resend.contacts.update({
|
||||
id: user.resendId,
|
||||
audienceId: process.env.RESEND_AUDIENCE,
|
||||
unsubscribed: false
|
||||
});
|
||||
|
||||
await prisma.user.update({
|
||||
where: {
|
||||
code: validation.data.code
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import prisma from '@prisma/prisma';
|
||||
import axios from 'axios';
|
||||
import { formatApiResponse } from '@utils/formatApiResponse';
|
||||
import {
|
||||
INTERNAL_SERVER_ERROR,
|
||||
@@ -19,17 +20,22 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
|
||||
try {
|
||||
const topStories: number[] = await fetch(getTopNews, {
|
||||
cache: 'no-store'
|
||||
}).then(res => res.json());
|
||||
const { data: topStories } = await axios.get<number[]>(getTopNews, {
|
||||
headers: {
|
||||
'Cache-Control': 'no-store'
|
||||
}
|
||||
});
|
||||
|
||||
console.info(`Top stories ids: ${topStories}`);
|
||||
|
||||
const newsPromises = topStories
|
||||
.slice(0, Number(process.env.NEWS_LIMIT))
|
||||
.map(id => fetch(getSingleNews(id)).then(res => res.json()));
|
||||
.map(id => axios.get<NewsDatabaseType>(getSingleNews(id)));
|
||||
|
||||
const news: NewsDatabaseType[] = await Promise.all(newsPromises);
|
||||
const newsResponses = await Promise.all(newsPromises);
|
||||
const news: NewsDatabaseType[] = newsResponses.map(
|
||||
response => response.data
|
||||
);
|
||||
|
||||
const upsertPromises = news.map(async getSingleNews => {
|
||||
const validation = NewsDatabaseSchema.safeParse(getSingleNews);
|
||||
@@ -81,7 +87,11 @@ export async function GET(request: NextRequest) {
|
||||
`Imported ${newsPromises.length} news.`
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.error('Axios error:', error.response?.data || error.message);
|
||||
} else {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
return formatApiResponse(
|
||||
STATUS_INTERNAL_SERVER_ERROR,
|
||||
INTERNAL_SERVER_ERROR
|
||||
|
||||
@@ -25,9 +25,6 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
|
||||
try {
|
||||
// send newsletter to users who didn't get it in the last 23h 50m, assuming a cron job every 10 minutes
|
||||
// this is to avoid sending the newsletter to the same users multiple times
|
||||
// this is not a perfect solution, but it's good enough for now
|
||||
const users = await prisma.user.findMany({
|
||||
where: {
|
||||
confirmed: true,
|
||||
|
||||
@@ -12,11 +12,10 @@ import {
|
||||
import { ResponseType, SubscribeFormSchema } from '@utils/validationSchemas';
|
||||
import * as crypto from 'crypto';
|
||||
import { NextRequest } from 'next/server';
|
||||
import { Resend } from 'resend';
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
if (!process.env.RESEND_KEY || !process.env.RESEND_AUDIENCE) {
|
||||
if (!process.env.RESEND_KEY) {
|
||||
throw new Error('RESEND_KEY is not set');
|
||||
}
|
||||
|
||||
@@ -36,8 +35,6 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
});
|
||||
|
||||
const resend = new Resend(process.env.RESEND_KEY);
|
||||
|
||||
const code = crypto
|
||||
.createHash('sha256')
|
||||
.update(`${process.env.SECRET_HASH}${email}}`)
|
||||
@@ -53,19 +50,6 @@ export async function POST(request: NextRequest) {
|
||||
deleted: false
|
||||
}
|
||||
});
|
||||
|
||||
const contact = await resend.contacts.get({
|
||||
id: user.resendId,
|
||||
audienceId: process.env.RESEND_AUDIENCE
|
||||
});
|
||||
|
||||
if (!contact) {
|
||||
await resend.contacts.update({
|
||||
id: user.resendId,
|
||||
audienceId: process.env.RESEND_AUDIENCE,
|
||||
unsubscribed: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const message: ResponseType = {
|
||||
@@ -84,21 +68,10 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const contact = await resend.contacts.create({
|
||||
email: email,
|
||||
audienceId: process.env.RESEND_AUDIENCE,
|
||||
unsubscribed: true
|
||||
});
|
||||
|
||||
if (!contact.data?.id) {
|
||||
throw new Error('Failed to create Resend contact');
|
||||
}
|
||||
|
||||
await prisma.user.create({
|
||||
data: {
|
||||
email,
|
||||
code,
|
||||
resendId: contact.data.id
|
||||
code
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -11,14 +11,11 @@ import {
|
||||
} from '@utils/statusCodes';
|
||||
import { ResponseType, UnsubscribeFormSchema } from '@utils/validationSchemas';
|
||||
import { NextRequest } from 'next/server';
|
||||
import { Resend } from 'resend';
|
||||
|
||||
export const dynamic = 'force-dynamic'; // defaults to force-static
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
if (!process.env.RESEND_KEY || !process.env.RESEND_AUDIENCE) {
|
||||
throw new Error('RESEND_AUDIENCE is not set');
|
||||
if (!process.env.RESEND_KEY) {
|
||||
throw new Error('Resend variables not set');
|
||||
}
|
||||
const body = await request.json();
|
||||
const validation = UnsubscribeFormSchema.safeParse(body);
|
||||
@@ -44,14 +41,6 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
});
|
||||
|
||||
const resend = new Resend(process.env.RESEND_KEY);
|
||||
|
||||
await resend.contacts.update({
|
||||
id: user.resendId,
|
||||
audienceId: process.env.RESEND_AUDIENCE,
|
||||
unsubscribed: true
|
||||
});
|
||||
|
||||
const sent = await sender([email], UnsubscribeTemplate());
|
||||
|
||||
if (!sent) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { CardDescription } from '@components/Card';
|
||||
import { CustomCard } from '@components/CustomCard';
|
||||
import { SchemaOrg } from '@components/SchemaOrg';
|
||||
import { ResponseType } from '@utils/validationSchemas';
|
||||
import axios from 'axios';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { Suspense, useEffect, useState } from 'react';
|
||||
|
||||
@@ -23,32 +24,31 @@ const ConfirmationPage = () => {
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/confirmation', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
const { data } = await axios.post<ResponseType>(
|
||||
'/api/confirmation',
|
||||
{
|
||||
code: code
|
||||
})
|
||||
});
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!res.ok) {
|
||||
if (!data.success) {
|
||||
router.push('/');
|
||||
return;
|
||||
}
|
||||
|
||||
const response: ResponseType = await res.json();
|
||||
|
||||
if (!response.success) {
|
||||
router.push('/');
|
||||
return;
|
||||
}
|
||||
|
||||
setMessage(response.message);
|
||||
setMessage(data.message);
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.error('Axios error:', error.response?.data || error.message);
|
||||
} else {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
router.push('/');
|
||||
}
|
||||
};
|
||||
|
||||
34
app/page.tsx
34
app/page.tsx
@@ -18,6 +18,7 @@ import {
|
||||
} from '@utils/validationSchemas';
|
||||
import { useState } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import axios from 'axios';
|
||||
|
||||
export const Home = () => {
|
||||
const [completed, setCompleted] = useState(false);
|
||||
@@ -45,29 +46,28 @@ export const Home = () => {
|
||||
async function handleSubmit(values: SubscribeFormType) {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await fetch('/api/subscribe', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
const { data } = await axios.post<ResponseType>(
|
||||
'/api/subscribe',
|
||||
{
|
||||
email: values.email
|
||||
})
|
||||
});
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!response?.ok) {
|
||||
throw new Error(`Invalid response: ${response.status}`);
|
||||
if (!data.success) {
|
||||
throw new Error(data.message);
|
||||
}
|
||||
|
||||
const formResponse: ResponseType = await response.json();
|
||||
|
||||
if (!formResponse.success) {
|
||||
throw Error(formResponse.message);
|
||||
}
|
||||
|
||||
setMessage(formResponse.message);
|
||||
setMessage(data.message);
|
||||
setCompleted(true);
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.error('Axios error:', error.response?.data || error.message);
|
||||
}
|
||||
setError(true);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
|
||||
@@ -16,6 +16,8 @@ import {
|
||||
UnsubscribeFormSchema,
|
||||
UnsubscribeFormType
|
||||
} from '@utils/validationSchemas';
|
||||
|
||||
import axios from 'axios';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
|
||||
@@ -52,29 +54,28 @@ const Unsubscribe = () => {
|
||||
async function handleSubmit(values: UnsubscribeFormType) {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await fetch('/api/unsubscribe', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
const { data } = await axios.post<ResponseType>(
|
||||
'/api/unsubscribe',
|
||||
{
|
||||
email: values.email
|
||||
})
|
||||
});
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!response?.ok) {
|
||||
throw new Error(`Invalid response: ${response.status}`);
|
||||
if (!data.success) {
|
||||
throw new Error(data.message);
|
||||
}
|
||||
|
||||
const formResponse: ResponseType = await response.json();
|
||||
|
||||
if (!formResponse.success) {
|
||||
throw Error(formResponse.message);
|
||||
}
|
||||
|
||||
setMessage(formResponse.message);
|
||||
setMessage(data.message);
|
||||
setCompleted(true);
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.error('Axios error:', error.response?.data || error.message);
|
||||
}
|
||||
setError(true);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
|
||||
Reference in New Issue
Block a user