Skip to content

Commit

Permalink
adding maps
Browse files Browse the repository at this point in the history
  • Loading branch information
IslemMedjahdi committed Jan 7, 2023
1 parent 9df3150 commit b1ae4c3
Show file tree
Hide file tree
Showing 15 changed files with 625 additions and 204 deletions.
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
"dependencies": {
"@headlessui/react": "^1.7.7",
"@next/font": "13.1.0",
"@react-google-maps/api": "^2.17.1",
"@tailwindcss/typography": "^0.5.8",
"@types/google-map-react": "^2.1.7",
"@types/node": "18.11.17",
"@types/nprogress": "^0.2.0",
"@types/react": "^18.0.26",
Expand All @@ -21,6 +23,8 @@
"axios": "^1.2.1",
"eslint": "8.30.0",
"eslint-config-next": "13.1.0",
"google-map-react": "^2.2.0",
"leaflet": "^1.9.3",
"next": "13.1.0",
"next-seo": "^5.15.0",
"nprogress": "^0.2.0",
Expand All @@ -31,6 +35,7 @@
"react-dom": "18.2.0",
"react-icons": "^4.7.1",
"react-image-picker-editor": "^1.2.0",
"react-leaflet": "^4.2.0",
"react-loader-spinner": "^5.3.4",
"react-quill": "^2.0.0",
"react-range": "^1.8.14",
Expand All @@ -41,6 +46,7 @@
"typescript": "4.9.4"
},
"devDependencies": {
"@types/react-leaflet": "^2.8.2",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-unused-imports": "^2.0.0",
"prettier": "^2.8.1",
Expand Down
Binary file added public/marker-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
218 changes: 17 additions & 201 deletions src/components/announcements/add-announcement/AddAnnouncementIndex.tsx
Original file line number Diff line number Diff line change
@@ -1,69 +1,28 @@
import dynamic from "next/dynamic";
import { useRouter } from "next/router";
import React, { useState } from "react";
import { ImagePickerConf } from "react-image-picker-editor";
import "react-image-picker-editor/dist/index.css";
import "react-quill/dist/quill.snow.css";
import { ICONS } from "../../../constants/icons";
import { INFO } from "../../../constants/info";

import { ROUTES } from "../../../constants/routes";

import { WILAYAS_FR } from "../../../constants/wilaya_algeria";
import AnnouncementService from "../../../services/annoucement.service";
import LocationService from "../../../services/locations.service";
import { Announcement } from "../../../typings/announcement";
import Select from "../../shared/Select";
import TextInput from "../../shared/TextInput";

const ReactQuill = dynamic(() => import("react-quill"), { ssr: false });
const ReactImagePickerEditor = dynamic(
() => import("react-image-picker-editor"),
{ ssr: false }
);
import AnnouncementForm from "./AnnouncementForm";
import LocalisationForm from "./LocalisationForm";
import PhotosPicker from "./PhotosPicker";

const locationService = LocationService.getInstance();
const announcementService = AnnouncementService.getInstance();

const config2: ImagePickerConf = {
borderRadius: "8px",
language: "en",
width: "100%",
height: "8rem",
objectFit: "cover",
compressInitial: null,
hideEditBtn: true,
hideDownloadBtn: true,
hideAddBtn: true,
};

const AddAnnouncementIndex = () => {
const router = useRouter();

const [announcement, setAnnouncement] =
useState<Announcement.AnnouncementNew>({});
const [photos, setPhotos] = useState<(Blob | null)[]>([]);
const [communes, setCommunes] = useState<string[]>([]);
const [loading, setLoading] = useState(false);

const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setAnnouncement((prev) => ({ ...prev, [e.target.name]: e.target.value }));
};

const onWilayaChange = async (wilaya: string) => {
setCommunes([]);
setAnnouncement((prev) => ({ ...prev, wilaya }));
setAnnouncement((prev) => ({ ...prev, commune: undefined }));
if (wilaya) {
try {
const response = await locationService.getCommunes(wilaya);
const communes = response.data.map(({ commune }: any) => commune);
setCommunes([""].concat(communes));
} catch (e) {
console.log(e);
}
}
};

const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (
Expand All @@ -75,7 +34,9 @@ const AddAnnouncementIndex = () => {
!announcement.commune ||
!announcement.wilaya ||
!announcement.surface ||
!announcement.prix
!announcement.prix ||
!announcement.longitude ||
!announcement.latitude
) {
return;
}
Expand All @@ -90,6 +51,8 @@ const AddAnnouncementIndex = () => {
bodyFormData.append("commune", announcement.commune);
bodyFormData.append("surface", announcement.surface.toString());
bodyFormData.append("prix", announcement.prix.toString());
bodyFormData.append("longitude", announcement.longitude.toString());
bodyFormData.append("latitude", announcement.latitude.toString());
photos.forEach(async (photo, index) => {
if (photo) {
bodyFormData.append("photos", photo, `image${index}.jpg`);
Expand Down Expand Up @@ -117,163 +80,16 @@ const AddAnnouncementIndex = () => {
</div>
<form onSubmit={onSubmit} className="w-full bg-white shadow">
<div className="flex flex-col gap-y-4 p-4">
<h1 className="flex items-center gap-x-2 font-serif text-sm font-medium text-gray-600">
<ICONS.Category />
<span>Information d'immobilier : </span>
</h1>
<TextInput
name="titre"
onChange={onChange}
type="text"
value={announcement.titre || ""}
label="Titre"
placeholder="Titre"
required
Icon={ICONS.Text}
<AnnouncementForm
announcement={announcement}
onAnnouncementChange={setAnnouncement}
/>
<Select
required
label="Catégorie"
className="!max-w-none"
placeholder="Sélectionnez Catégorie"
options={INFO.IMMOBILIER_CATEGORY}
value={announcement.categorie || ""}
onChange={(selected) =>
setAnnouncement((prev) => ({
...prev,
categorie: selected as Announcement.Category,
}))
}
/>
<Select
required
label="Type"
className="!max-w-none"
placeholder="Sélectionnez Type"
options={INFO.IMMOBILIER_TYPES}
value={announcement.type || ""}
onChange={(selected) =>
setAnnouncement((prev) => ({
...prev,
type: selected,
}))
}
/>
<TextInput
name="prix"
onChange={(e) =>
setAnnouncement((prev) => ({
...prev,
prix: parseInt(e.target.value) || 0,
}))
}
type="text"
value={announcement.prix?.toString() || ""}
label="Prix"
placeholder="Prix"
Icon={ICONS.Price}
required
/>
<TextInput
name="surface"
type="text"
value={announcement.surface?.toString() || ""}
onChange={(e) =>
setAnnouncement((prev) => ({
...prev,
surface: parseInt(e.target.value) || 0,
}))
}
label="Surface"
placeholder="Surface"
required
Icon={ICONS.Surface}
/>
<div>
<label
htmlFor={"description"}
className="flex items-center gap-x-1 text-sm font-medium text-gray-600 "
>
<span>Description</span>
<span className="text-red-500">*</span>
</label>
<ReactQuill
id="description"
theme="snow"
className="mt-2 flex max-h-48 flex-col rounded"
value={announcement.description}
onChange={(value) =>
setAnnouncement((prev) => ({ ...prev, description: value }))
}
/>
</div>
<div>
<label
htmlFor={"description"}
className="flex items-center gap-x-1 text-sm font-medium text-gray-600 "
>
<span>Photos</span>
<span className="text-red-500">*</span>
</label>
<div className="mt-2 flex flex-wrap items-center justify-center gap-4 md:justify-start">
{[0, 1, 2, 3].map((item) => (
<div className="w-full max-w-[12rem] grow" key={item}>
<ReactImagePickerEditor
config={config2}
imageChanged={async (newDataUri: any) => {
const blob = newDataUri
? await (await fetch(newDataUri)).blob()
: null;
setPhotos((prev) => {
let newPhotos = [...prev];
newPhotos[item] = blob;
return newPhotos;
});
}}
/>
</div>
))}
</div>
</div>
<hr></hr>
<h1 className="flex items-center gap-x-2 font-serif text-sm font-medium text-gray-600">
<ICONS.Map />
<span>Informations de localisation : </span>
</h1>
<div className="grid w-full grid-cols-1 items-center justify-center gap-2 sm:grid-cols-2">
<Select
required
label="Wilaya"
className="!max-w-none"
placeholder="Sélectionnez Wilaya"
options={WILAYAS_FR}
value={announcement.wilaya || ""}
onChange={(selected) => {
onWilayaChange(selected);
}}
/>
<Select
required
label="Commune"
className="!max-w-none"
placeholder="Sélectionnez Commune"
options={communes}
disabled={communes.length === 0}
value={announcement.commune || ""}
onChange={(selected) =>
setAnnouncement((prev) => ({ ...prev, commune: selected }))
}
/>
</div>
<TextInput
name="adresse"
onChange={onChange}
type="text"
value={announcement.adresse || ""}
label="Adresse"
placeholder="Adresse"
required
Icon={ICONS.Map}
<PhotosPicker onImageChange={setPhotos} />
<hr></hr>
<LocalisationForm
announcement={announcement}
onAnnouncementChange={setAnnouncement}
/>
</div>
<hr />
Expand Down
Loading

0 comments on commit b1ae4c3

Please sign in to comment.