Skip to content

Commit

Permalink
Add new structure and fix server actions errors
Browse files Browse the repository at this point in the history
  • Loading branch information
JohanMejia77 committed Aug 11, 2024
1 parent 094ca06 commit 7f09462
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 66 deletions.
13 changes: 13 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM node:20-alpine

WORKDIR /app

COPY package*.json .

RUN npm install

COPY . .

EXPOSE 3000

CMD npm run dev
11 changes: 10 additions & 1 deletion next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'http',
hostname: 'localhost',
},
],
}
};

export default nextConfig;
34 changes: 20 additions & 14 deletions src/actions/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,28 @@
import { REVIEWS_API } from "@/lib/constants";

export const login = async (email: string, password: string) => {
const response = await fetch(`${REVIEWS_API}/admin-users/logIn`, {
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ thisUser: email, pass: password }),
method: "POST",
});

const data = await response.json();
try {
const response = await fetch(`${REVIEWS_API}/admin-users/logIn`, {
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ thisUser: email, pass: password }),
method: "POST",
});

if (data.statusCode === 401) {
const data = await response.json();

if (data.statusCode === 401) {
return {
error: "Acceso no autorizado",
};
}
return {
error: "Acceso no autorizado",
token: data.access_token,
};
} catch (error) {
return {
error: "Error al intentar iniciar sesión, intente más tarde",
}
}
return {
token: data.access_token,
};
};
78 changes: 44 additions & 34 deletions src/actions/reviews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,41 @@ export const getReviews = async (): Promise<Review[]> => {
try {
const response = await fetch(`${REVIEWS_API}/reviews`);
const { data } = await response.json();
return data;
return data ?? [];
} catch (_) {
return [];
}
};
export const createReview = async (
review: z.infer<typeof reviewSchema>,
image: File,
token: string
) => {
const newReview = {
review: review.review,
rating: String(review.rating),
user: review.user,
date: new Date(),
};

const response = await fetch(`${REVIEWS_API}/reviews`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(newReview),
});
if (!response.ok) {
export const createReview = async (formData: FormData, token: string) => {
try {
const response = await fetch(`${REVIEWS_API}/reviews`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
body: formData,
});
const data = await response.json();
if (!response.ok && response.status == 401) {
return {
error: "Su sesión ha expirado, ingrese nuevamente",
};
}
if (!response.ok) {
return {
error: data.message,
};
}
revalidatePath("atc24$rw/admin");
revalidatePath("/");
return {
error: "Su sesión ha expirado, ingrese nuevamente",
success: "Se creó una nueva reseña",
};
} catch (error) {
return {
error: "Error al crear la reseña",
};
}

revalidatePath("atc24$rw/admin");
revalidatePath("/");
return {
success: "Se creó una nueva reseña",
};
};
export const deleteReview = async (id: string, token: string) => {
const response = await fetch(`${REVIEWS_API}/reviews/${id}`, {
Expand All @@ -54,31 +53,42 @@ export const deleteReview = async (id: string, token: string) => {
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
const data = await response.json();
if (!response.ok && response.status == 401) {
return {
error: "Su sesión ha expirado, ingrese nuevamente",
};
}
if (!response.ok) {
return {
error: data.message,
};
}
revalidatePath("atc24$rw/admin");
revalidatePath("/");
return {
success: "Se eliminó la reseña",
};
};
export const updateReview = async (updatedReview: Review, token: string) => {
export const updateReview = async (formData: FormData, token: string) => {
const response = await fetch(`${REVIEWS_API}/reviews`, {
method: "PATCH",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(updatedReview),
body: formData,
});
if (!response.ok) {
const data = await response.json();
if (!response.ok && response.status == 401) {
return {
error: "Su sesión ha expirado, ingrese nuevamente",
};
}
if (!response.ok) {
return {
error: data.message,
};
}

revalidatePath("atc24$rw/admin");
revalidatePath("/");
Expand Down
4 changes: 2 additions & 2 deletions src/app/(admin)/atc24$rw/admin/components/DeleteAlert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface DeleteAlertProps {
export const DeleteAlert = ({ children, onDelete }: DeleteAlertProps) => {
return (
<AlertDialog>
<AlertDialogTrigger>{children}</AlertDialogTrigger>
<AlertDialogTrigger className="w-full flex justify-end items-center">{children}</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
Expand All @@ -26,7 +26,7 @@ export const DeleteAlert = ({ children, onDelete }: DeleteAlertProps) => {
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancelar</AlertDialogCancel>
<AlertDialogAction onClick={onDelete}>Confirmar</AlertDialogAction>
<AlertDialogAction onClick={onDelete} className="bg-primary-lm dark:text-white hover:dark:bg-primary-lm/85">Confirmar</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
Expand Down
42 changes: 35 additions & 7 deletions src/app/(admin)/atc24$rw/admin/components/ReviewForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { toast } from "sonner";
import { Textarea } from "@/components/ui/textarea";
import { useDropzone } from "react-dropzone";
import Image from "next/image";
import { REVIEWS_API } from "@/lib/constants";

interface ReviewFormProps {
review?: Review;
Expand All @@ -50,41 +51,59 @@ export const ReviewForm = ({ review }: ReviewFormProps) => {
review: review?.review || "",
rating: review?.rating || "5",
user: review?.user || "",
active: review?.active || "false"
active: review?.active || "false",
},
});

const handleCreate = (
values: z.infer<typeof reviewSchema>,
token: string
) => {
const formData = new FormData();
formData.append("review", values.review);
formData.append("rating", String(values.rating));
formData.append("user", values.user);
formData.append("date", new Date().toISOString());
formData.append("file", acceptedFiles[0]);
formData.append("active", JSON.parse(values.active || "false") ? "true" : "false");

startTransition(() => {
createReview(values, acceptedFiles[0], token)
createReview(formData, token)
.then((data) => {
if (data.success) {
toast.success(data.success);
onClose();
}
if (data.error) {
toast.error(data.error);
router.push("/atc24$rw");
// router.push("/atc24$rw");
}
})
.catch(() => toast.error("Ocurrió un error"));
});
};

const handleUpdate = (review: Review, token: string) => {
const formData = new FormData();
formData.append("id", review.id);
formData.append("review", review.review);
formData.append("rating", String(review.rating));
formData.append("user", review.user);
formData.append("date", new Date().toISOString());
formData.append("file", acceptedFiles[0] || new File([], "null", {
type: "image/png",
}));
formData.append("active", review.active ? "true" : "false");
startTransition(() => {
updateReview(review, token)
updateReview(formData, token)
.then((data) => {
if (data.success) {
toast.success(data.success);
onClose();
}
if (data.error) {
toast.error(data.error);
router.push("/atc24$rw");
// router.push("/atc24$rw");
}
})
.catch(() => toast.error("Ocurrió un error"));
Expand Down Expand Up @@ -159,7 +178,15 @@ export const ReviewForm = ({ review }: ReviewFormProps) => {
className="w-full p-4 shadow-sm text-sm text-muted-foreground rounded-md border border-input bg-transparent flex flex-col items-center justify-center"
>
<Input type="file" {...getInputProps()} />
{acceptedFiles[0] ? (
{review?.image && !acceptedFiles[0] ? (
<Image
src={`${REVIEWS_API}/images/reviews/${review.image}`}
width={150}
height={150}
className="aspect-square object-cover"
alt="Imagen del usuario"
/>
) : acceptedFiles[0] ? (
<Image
src={URL.createObjectURL(acceptedFiles[0])}
width={150}
Expand Down Expand Up @@ -191,6 +218,7 @@ export const ReviewForm = ({ review }: ReviewFormProps) => {
type="checkbox"
id="show"
className="w-5 h-5"
checked={JSON.parse(field.value || 'false') ? true : false}
/>
<label
htmlFor="show"
Expand All @@ -204,7 +232,7 @@ export const ReviewForm = ({ review }: ReviewFormProps) => {
)}
/>
<Button
className="w-full bg-primary-lm hover:bg-red-600"
className="w-full bg-primary-lm hover:bg-red-600 dark:text-white"
disabled={isPending}
>
{!isPending ? (
Expand Down
16 changes: 10 additions & 6 deletions src/app/(admin)/atc24$rw/admin/components/ReviewsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table";
import Image from "next/image";
import { Review } from "@/types";
import { CiEdit, CiTrash } from "react-icons/ci";
import { useReviewFormModal } from "@/store/useReviewFormModal";
Expand All @@ -16,6 +17,7 @@ import { DeleteAlert } from "./DeleteAlert";
import { toast } from "sonner";
import { useTransition } from "react";
import { useRouter } from "next/navigation";
import { REVIEWS_API } from "@/lib/constants";

interface ReviewsTableProps {
reviews: Review[];
Expand All @@ -40,7 +42,7 @@ export const ReviewsTable = ({ reviews }: ReviewsTableProps) => {
}
if (data.error) {
toast.error(data.error);
router.push("/atc24$rw");
// router.push("/atc24$rw");
}
})
.catch(() => toast.error("Ocurrió un error al eliminar la reseña"));
Expand All @@ -52,7 +54,7 @@ export const ReviewsTable = ({ reviews }: ReviewsTableProps) => {
<Table>
<TableHeader>
<TableRow>
<TableHead>Id</TableHead>
<TableHead>Imagen del usuario</TableHead>
<TableHead>Texto</TableHead>
<TableHead>Calificación</TableHead>
<TableHead>Usuario</TableHead>
Expand All @@ -65,8 +67,10 @@ export const ReviewsTable = ({ reviews }: ReviewsTableProps) => {
<TableBody>
{reviews.map((review) => (
<TableRow key={review.id}>
<TableCell>{review.id}</TableCell>
<TableCell>{review.review}</TableCell>
<TableCell>
<Image src={`${REVIEWS_API}/images/reviews/${review.image}`} className="rounded-full aspect-square object-cover" width={100} height={100} alt="Imagen del usuario" />
</TableCell>
<TableCell className="max-w-[15rem] pr-6">{review.review}</TableCell>
<TableCell>{review.rating}</TableCell>
<TableCell>{review.user}</TableCell>
<TableCell>
Expand All @@ -76,9 +80,9 @@ export const ReviewsTable = ({ reviews }: ReviewsTableProps) => {
className="cursor-pointer"
/>
</TableCell>
<TableCell className="flex items-center justify-end">
<TableCell>
<DeleteAlert onDelete={() => handleDelele(review.id)}>
<CiTrash size={25} className="cursor-pointer" />
<CiTrash size={25} className="cursor-pointer hover:text-red-500" />
</DeleteAlert>
</TableCell>
</TableRow>
Expand Down
2 changes: 1 addition & 1 deletion src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,4 @@ export const PAYMENT_METHODS = [
description: 'Tu seguridad es nuestra prioridad. Utilizamos tecnología SSL y métodos de pago verificados para proteger tus datos sin riesgos.'
}
]
export const REVIEWS_API = "https://landingatc-back-end.onrender.com"
export const REVIEWS_API = process.env.REVIEWS_API || "http://localhost:3005"
2 changes: 1 addition & 1 deletion src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ export interface Review {
review: string;
rating: string;
user: string;
image: File,
image: File | string,
active?: string;
}

0 comments on commit 7f09462

Please sign in to comment.