Skip to content

Commit

Permalink
adding posted announcements, delete
Browse files Browse the repository at this point in the history
  • Loading branch information
IslemMedjahdi committed Jan 5, 2023
1 parent f68bb13 commit 274885d
Show file tree
Hide file tree
Showing 18 changed files with 330 additions and 21 deletions.
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@headlessui/react": "^1.7.7",
"@next/font": "13.1.0",
"@types/node": "18.11.17",
"@types/react": "18.0.26",
"@types/react": "^18.0.26",
"@types/react-dom": "18.0.9",
"autoprefixer": "^10.4.13",
"axios": "^1.2.1",
Expand All @@ -22,9 +22,12 @@
"next-seo": "^5.15.0",
"postcss": "^8.4.20",
"react": "18.2.0",
"react-data-table-component": "^7.5.3",
"react-dom": "18.2.0",
"react-icons": "^4.7.1",
"react-loader-spinner": "^5.3.4",
"styled-components": "^5.3.6",
"swiper": "^8.4.5",
"tailwindcss": "^3.2.4",
"typescript": "4.9.4"
},
Expand Down
Binary file added public/no-image-available.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/components/layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ const Layout: React.FC<Props> = ({
const { currentUser } = useAuth();

return (
<div>
<div className="min-h-screen bg-gray-50">
{currentUser && withHeader && <Header />}
<div className="min-h-screen bg-gray-50">{children}</div>
<div>{children}</div>
{currentUser && withFooter && <Footer />}
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import ProfileMenu from "./ProfileMenu";

const Header = () => {
return (
<header className="flex justify-center border-b">
<header className="sticky top-0 z-50 flex justify-center border-b bg-white">
<div className="container flex items-center justify-between gap-x-4 py-4 px-4">
<div className="flex items-center gap-x-4">
<Link
Expand Down
202 changes: 201 additions & 1 deletion src/components/posted-announcement/PostedAnnouncementIndex.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,207 @@
import Image from "next/image";
import Link from "next/link";
import { useEffect, useState } from "react";
import DataTable, { TableColumn } from "react-data-table-component";
import { Autoplay } from "swiper";
import { Swiper, SwiperSlide } from "swiper/react";
import { ICONS } from "../../constants/icons";
import { IMAGES } from "../../constants/images";
import { ROUTES } from "../../constants/routes";
import AnnouncementService from "../../services/annoucement.service";
import { Announcement } from "../../typings/announcement";
import Loading from "../shared/Loading";
// Import Swiper styles
import "swiper/css";

const announcementService = AnnouncementService.getInstance();

const columns: TableColumn<Announcement.AnnouncementPart>[] = [
{
name: "N",
cell: (_, index) => (
<span className="text-sm font-medium">{index + 1}</span>
),
selector: (_, index) => index || 0,
sortable: true,
width: "1rem",
},
{
name: "Photos",
cell: (row, index) => (
<>
{true || (row.photos && row.photos.length > 0) ? (
<>
<Swiper
modules={[Autoplay]}
loop={true}
autoplay={{
disableOnInteraction: false,
pauseOnMouseEnter: true,
delay: index % 2 ? 3000 : 4000,
}}
>
{[
IMAGES.Auth_background,
IMAGES.Auth_background_mobile,
IMAGES.NO_IMAGE,
].map((item, index) => (
<SwiperSlide key={index} className="!w-full">
<Image
src={item}
alt="no-image"
className="aspect-video h-36 object-cover"
width={720}
height={480}
/>
</SwiperSlide>
))}
</Swiper>
</>
) : (
<Image
src={IMAGES.NO_IMAGE}
alt="no-image"
className="aspect-video h-36 object-cover"
width={720}
height={480}
/>
)}
</>
),
grow: 3,
},
{
name: "Catégorie",
cell: (row) => <p className="text-sm font-medium">{row.categorie}</p>,
selector: (row) => row.categorie,
reorder: true,
sortable: true,
grow: 1,
},
{
name: "Surface",
cell: (row) => (
<p className="text-sm font-medium">
{row.surface + " Km²" || "indéfini"}
</p>
),
selector: (row) => row.surface || 0,
sortable: true,
reorder: true,
grow: 1,
},
{
name: "Prix",
cell: (row) => <p className="text-sm font-medium">{row.prix + " DZD"}</p>,
selector: (row) => row.prix,
sortable: true,
reorder: true,
grow: 1,
},
{
name: "Type",
cell: (row) => (
<p className="text-sm font-medium">{row.type || "indéfini"}</p>
),
selector: (row) => row.type || "indéfini",
sortable: true,
reorder: true,
grow: 1,
},
{
name: "Actions",
cell: (row) => {
const [deleteLoading, setDeleteLoading] = useState<boolean>(false);

const deleteAnnounceHandler = async () => {
try {
const response = await announcementService.deleteAnnouncement(row.id);
window.location.reload();
} catch (e) {
console.log(e);
} finally {
setDeleteLoading(false);
}
};

return (
<div className="flex flex-wrap gap-2">
<button
disabled={deleteLoading}
onClick={deleteAnnounceHandler}
className={`${
deleteLoading ? "animate-pulse" : ""
} flex items-center gap-x-1 rounded-sm bg-red-500 px-2 py-1 text-sm font-medium text-white transition duration-200 hover:bg-red-400`}
>
<ICONS.Delete />
<span className="whitespace-nowrap">Supprimer</span>
</button>
<Link
href={ROUTES.ANNOUNCEMENT_BY_ID.path + row.id}
className="flex items-center gap-x-1 rounded-sm bg-blue-primary px-2 py-1 text-sm font-medium text-white transition duration-200 hover:bg-blue-hover"
>
<ICONS.Eye />
<span className="whitespace-nowrap">Aperçu</span>
</Link>
</div>
);
},
grow: 2.5,
},
];

const PostedAnnouncementIndex: React.FC = () => {
const [announcements, setAnnouncements] = useState<
Announcement.AnnouncementPart[] | null
>(null);
const [loading, setLoading] = useState<boolean>(true);

const getMyAnnouncements = async () => {
setLoading(true);
try {
const response = await announcementService.getMyAnnouncements();
setAnnouncements(response.data);
} catch (e) {
console.log(e);
} finally {
setLoading(false);
}
};

useEffect(() => {
getMyAnnouncements();
}, []);

return (
<div className="flex justify-center">
<div className="container">PostedAnnouncement</div>
<div className="container max-w-screen-lg px-4">
<div className="flex justify-center py-10">
<h1 className="relative z-10 text-center font-serif text-3xl font-semibold after:absolute after:top-full after:left-0 after:h-2 after:w-full after:origin-left after:skew-y-1 after:animate-reveal after:bg-blue-primary">
Vos announces déposées
</h1>
</div>
<div className="shadow">
<DataTable
columns={columns}
data={announcements || []}
customStyles={{
headCells: {
style: {
fontWeight: 700,
fontFamily: "'Merriweather', sarif",
},
},
}}
pagination
progressPending={loading}
progressComponent={
<div className="flex w-full justify-center dark:bg-slate-800">
<Loading />
</div>
}
/>
</div>
</div>
</div>
);
};
Expand Down
18 changes: 8 additions & 10 deletions src/components/shared/Loading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@ import { RotatingSquare } from "react-loader-spinner";

const Loading = () => {
return (
<div className="flex h-screen w-screen items-center justify-center bg-white">
<RotatingSquare
height="100"
width="100"
color="#1C3988"
ariaLabel="rotating-square-loading"
strokeWidth="4"
visible={true}
/>
</div>
<RotatingSquare
height="100"
width="100"
color="#1C3988"
ariaLabel="rotating-square-loading"
strokeWidth="4"
visible={true}
/>
);
};

Expand Down
4 changes: 4 additions & 0 deletions src/constants/icons.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import {
BsBookmarkHeart,
BsEnvelope,
BsEye,
BsFolder,
BsGear,
BsPersonX,
BsTrash,
} from "react-icons/bs";
import { FiMenu } from "react-icons/fi";

Expand All @@ -14,4 +16,6 @@ export const ICONS = {
Posted: BsFolder,
SignOut: BsPersonX,
Settings: BsGear,
Delete: BsTrash,
Eye: BsEye,
};
1 change: 1 addition & 0 deletions src/constants/images.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export const IMAGES = {
Logo: "/logo.svg",
Auth_background_mobile: "/auth-background1.png",
Auth_background: "/auth-background2.png",
NO_IMAGE: "/no-image-available.png",
};
6 changes: 6 additions & 0 deletions src/constants/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ export const ROUTES = {
allowedRoles: [ROLES.USER],
Icon: ICONS.Favorite,
},
ANNOUNCEMENT_BY_ID: {
name: "Announcement",
path: "/announcements/",
pathname: "/announcements/[:id]",
allowedRoles: [ROLES.USER],
},
MESSAGES: {
name: "Mes messages",
path: "/messages",
Expand Down
6 changes: 5 additions & 1 deletion src/context/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,11 @@ const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
.find(([_, item]) => item.pathname === router.pathname)?.[1]
.allowedRoles.includes(currentUser.role))
) {
return <Loading />;
return (
<div className="flex h-screen w-screen items-center justify-center bg-white">
<Loading />;
</div>
);
}

return (
Expand Down
21 changes: 20 additions & 1 deletion src/services/annoucement.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//import axios from "../constants/axios";
import axios from "../constants/axios";

class AnnouncementService {
private static instance: AnnouncementService;
Expand All @@ -8,10 +8,29 @@ class AnnouncementService {
}
return this.instance;
}

constructor() {
console.log("AnnouncementService constructor");
}

public async getMyAnnouncements() {
try {
const response = await axios.get("/announcements/");
return response;
} catch (e) {
throw e;
}
}

public async deleteAnnouncement(id: number) {
try {
const response = await axios.delete(`/announcements/${id}/delete`);
return response;
} catch (e) {
throw e;
}
}

// here put all announcements requests
}

Expand Down
4 changes: 2 additions & 2 deletions src/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ class AuthService {
console.log("AuthService constructor");
}

public async postGoogleCredential(credentials: any) {
public async postGoogleCredential(credentials: string) {
try {
const res = await axios.post("/auth", JSON.stringify({ credentials }));
const res = await axios.post("/auth/", JSON.stringify({ credentials }));
return res;
} catch (e) {
throw e;
Expand Down
21 changes: 21 additions & 0 deletions src/typings/announcement.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Auth } from "./user";

declare module Announcement {
type Announcement = {
id: number;
type?: string;
surface?: number;
description?: string;
prix: number;
categorie: Category;
auteur: Auth.User[];
fans?: Auth.User[];
photos: Commun.Image[];
};

type Category = "Vente" | "Echange" | "Location" | "Location pour vacances";

type AnnouncementPart = Omit<Announcement, "photos" | "fans" | "auteur"> & {
photos: Commun.Image[];
};
}
Loading

0 comments on commit 274885d

Please sign in to comment.