Skip to content

Commit

Permalink
add company on leaflet map
Browse files Browse the repository at this point in the history
  • Loading branch information
Jantero93 committed Jun 9, 2024
1 parent 641f801 commit fcff759
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 81 deletions.
2 changes: 1 addition & 1 deletion MapServer/Data/DTOs/LocationDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public record LocationDto
public required double Latitude { get; init; }
public required string Street { get; init; }
public required string RoadNumber { get; init; }
public required string City { get; init; }
public string? Suburban { get; init; }
public string? City { get; init; }
public string? PostalCode { get; init; }
}
27 changes: 27 additions & 0 deletions MapServer/Mappers/CompanyMapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using MapServer.Data.DTOs;
using MapServer.Data.Models;
using MapServer.Store.Models;

namespace MapServer.Mappers;

public static class CompanyMapper
{
public static CompanyDto MapLocationAndCompanyToDto(Location l, Company c) => new()
{
Id = c.Id,
CompanyName = c.CompanyName,
EstablishmentDate = c.EstablishmentDate,
ClosureDate = c.ClosureDate,
Location = new()
{
Id = l.Id,
City = l.City,
Latitude = l.Latitude,
Longitude = l.Longitude,
RoadNumber = l.StreetNumber,
Street = l.Street,
PostalCode = l.PostalCode,
Suburban = l.Suburb
}
};
}
25 changes: 6 additions & 19 deletions MapServer/Services/CompanyService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using MapServer.Data.DTOs;
using MapServer.Data.Interfaces;
using MapServer.Data.Models;
using MapServer.Mappers;
using MapServer.Services.Interfaces;
using MapServer.Store.Models;

Expand Down Expand Up @@ -30,10 +31,13 @@ public async Task<CompanyDto> AddNewCompany(AddNewCompanyRequest request)

logger.LogInformation("Added to db new Location with Id: {Id}", location.Id);

// Reset Datetime
var establishmentDate = request.EstablishmentDate.ToUniversalTime().Date;

Company newCompany = new()
{
CompanyName = request.CompanyName,
EstablishmentDate = request.EstablishmentDate,
EstablishmentDate = establishmentDate,
ClosureDate = null,
LocationId = location.Id
};
Expand All @@ -42,24 +46,7 @@ public async Task<CompanyDto> AddNewCompany(AddNewCompanyRequest request)

logger.LogInformation("Added to db new Company with Id: {Id}", company.Id);

CompanyDto dto = new()
{
Id = company.Id,
CompanyName = company.CompanyName,
EstablishmentDate = company.EstablishmentDate,
ClosureDate = company.ClosureDate,
Location = new LocationDto
{
Id = location.Id,
City = location.City,
Latitude = location.Latitude,
Longitude = location.Longitude,
Street = location.Street,
RoadNumber = location.StreetNumber,
PostalCode = location.PostalCode,
Suburban = location.Suburb
}
};
var dto = CompanyMapper.MapLocationAndCompanyToDto(location, company);

logger.LogInformation("Returning new CompanyDto: {@CompanyDto}", dto);

Expand Down
6 changes: 5 additions & 1 deletion react-client/src/store/slices/generalUiSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import { ThemeType } from "@/theme/theme";
import { FALLBACK_THEME } from "@/utilities/env";
import LocalStorageService from "@/services/LocalStorageService";
import { ControlPanelComponents } from "@/views/mapView/ControlPanelItems/components/componentsConstants";
import { ControlPanelComponents } from "@/views/mapView/ControlPanelItems/ControlPanel";
import { RootState } from "../store";

// INFO: ViewCompany just for testing purposes, not actual component
export type ControlViewComponent = keyof typeof ControlPanelComponents;
Expand Down Expand Up @@ -74,4 +75,7 @@ export const {
clearControlViewComponent,
} = generalUiSlice.actions;

export const selectedControllerComponent = (state: RootState) =>
state.ui.selectedControlViewComponent;

export default generalUiSlice.reducer;
52 changes: 27 additions & 25 deletions react-client/src/utilities/dateHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,37 +24,39 @@ export const isTimeBeforeCurrentUtc = (date: string | Date): boolean =>
export const isTimeAfterCurrentUtc = (date: string | Date): boolean =>
moment(date).isAfter(moment().utc());

/**
* Get current time on JavaScript Date, current year, current hour etc. Check parametets
* @param format
* @returns Return current time on wanted parameter type
*/
export const getCurrentDates = (
format?: "year" | "month" | "week" | "day" | "hour"
): number => {
switch (format) {
case "year":
return moment().year();
case "month":
return moment().month();
case "week":
return moment().week();
case "day":
return moment().day();
case "hour":
return moment().hour();
default:
return moment().year();
}
};

/**
* Checks is given year same or before compareTo, compareTo defaults to current year
*/
export const isYearSameOrBefore = (year: string, compareTo?: string) => {
export const isYearSameOrBefore = (
year: string,
compareTo?: string
): boolean => {
const inputYear = moment(year, "YYYY", true);

const compareYear = compareTo ? moment() : moment(compareTo, "YYYY", true);

return inputYear.isSameOrBefore(compareYear);
};

/**
* Creates Javascript object from given string. Returns on utc time
* If format YYYY, first day and month of year will be provided
* @throws If format and input doesn't pass moment's strict check
*/
export const createJsDateFromString = (
dateString: string,
format = "YYYY-MM-DD"
): Date => {
const parsedMoment =
format === "YYYY"
? moment(dateString + "-01-02", "YYYY-MM-DD", true)
: moment(dateString, format, true);

if (!parsedMoment.isValid()) {
throw new Error(
`Moment not valid: dateString=${dateString}, format=${format}`
);
}

return parsedMoment.utc().toDate();
};
23 changes: 18 additions & 5 deletions react-client/src/views/mapView/ControlPanelItems/ControlPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
import { Stack, styled } from "@mui/material";
import { Stack, Typography, styled } from "@mui/material";
import { useAppSelector } from "@/hooks/useStoreHooks";
import SelectControlPanelDropdown from "@/views/mapView/ControlPanelItems/SelectControlPanelDropdown";
import { ComponentMap } from "@/views/mapView/ControlPanelItems/components/componentsConstants";
import { selectedControllerComponent } from "@/store/slices/generalUiSlice";
import AddCompanyComponent from "@/views/mapView/ControlPanelItems/components/AddCompanyComponent";

const PaddedStack = styled(Stack)(({ theme }) => ({
padding: theme.spacing(4),
padding: theme.spacing(2),
}));
export const ControlPanelComponents = {
InitialView: "InitialView",
AddCompany: "AddCompany",
GetCompanies: "GetCompanies",
} as const;

const { AddCompany, GetCompanies, InitialView } = ControlPanelComponents;

const ComponentMap: Record<string, JSX.Element> = {
[AddCompany]: <AddCompanyComponent />,
[InitialView]: <Typography>Very good initial view</Typography>,
[GetCompanies]: <Typography>Get companies</Typography>,
};
const ControlPanel = () => {
const selectedControlViewComponent = useAppSelector(
(s) => s.ui.selectedControlViewComponent
selectedControllerComponent
);

return (
<PaddedStack>
<PaddedStack spacing={1}>
<SelectControlPanelDropdown />
{ComponentMap[selectedControlViewComponent]}
</PaddedStack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
SelectChangeEvent,
} from "@mui/material";
import { useAppDispatch, useAppSelector } from "@/hooks/useStoreHooks";
import { ControlPanelComponents } from "@/views/mapView/ControlPanelItems/components/componentsConstants";
import { ControlPanelComponents } from "@/views/mapView/ControlPanelItems/ControlPanel";
import {
ControlViewComponent,
setControlViewComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,24 @@ import {
AddCompanyRequest,
postNewCompany,
} from "@/store/actions/companyActions";
import { selectValidMapLocation } from "@/store/slices/uiMapSlice";
import { isYearSameOrBefore } from "@/utilities/dateHelpers";
import { Box, Button, TextField, TextFieldProps, styled } from "@mui/material";
import { selectedControllerComponent } from "@/store/slices/generalUiSlice";
import {
clearLocation,
selectValidMapLocation,
} from "@/store/slices/uiMapSlice";
import {
createJsDateFromString,
isYearSameOrBefore,
} from "@/utilities/dateHelpers";
import {
Box,
Button,
TextField,
TextFieldProps,
Typography,
styled,
} from "@mui/material";
import { useEffect } from "react";
import { Field, Form } from "react-final-form";

const StyledTextField = styled(({ ...otherProps }: TextFieldProps) => (
Expand All @@ -22,13 +37,23 @@ const FormContainer = styled("form")(({ theme }) => ({
}));

const AddCompany = () => {
const storeLocation = useAppSelector((s) => s.uiMap);
const dispatch = useAppDispatch();

const mapLocation = useAppSelector(selectValidMapLocation);
const controllerComponent = useAppSelector(selectedControllerComponent);

// Clear location selection when component is changed
useEffect(() => {
if (controllerComponent !== "AddCompany") {
dispatch(clearLocation());
}
return () => {
dispatch(clearLocation());
};
}, [dispatch, controllerComponent]);

if (mapLocation === null) {
return <div>Error on map location. ReClick location</div>;
return <Typography>Select position from map</Typography>;
}
const initializedFormValues = {
streetAddress: mapLocation.streetAddress,
Expand Down Expand Up @@ -64,7 +89,10 @@ const AddCompany = () => {
) => {
const companyData = {
...formValues,
establishmentDate: new Date(Number(formValues.establishmentDate), 0),
establishmentDate: createJsDateFromString(
formValues.establishmentDate.toString(),
"YYYY"
),
};
const payload: AddCompanyRequest = {
...companyData,
Expand All @@ -84,16 +112,13 @@ const AddCompany = () => {
<FormContainer onSubmit={handleSubmit}>
<Field
name="streetAddress"
initialValue={storeLocation.streetAddress}
initialValue={mapLocation.streetAddress}
>
{({ input }) => (
<StyledTextField {...input} label="Street Address" disabled />
)}
</Field>
<Field
name="streetNumber"
initialValue={storeLocation.streetNumber}
>
<Field name="streetNumber" initialValue={mapLocation.streetNumber}>
{({ input }) => (
<StyledTextField {...input} label="Street Number" disabled />
)}
Expand Down

This file was deleted.

28 changes: 26 additions & 2 deletions react-client/src/views/mapView/mapComponents/LeafletMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import L from "leaflet";
import DefaultMarkerIcon2x from "@/assets/map/default-marker-icon-2x.png";
import DefaultMarkerIcon from "@/assets/map/default-marker-icon.png";
import DefaultMarkerShadow from "@/assets/map/default-marker-shadow.png";
import { useAppSelector, useAppDispatch } from "@/hooks/useStoreHooks";
import { setLocation } from "@/store/slices/uiMapSlice";
import {
selectedControllerComponent,
setSnackbarText,
} from "@/store/slices/generalUiSlice";
import GeocodingService from "@/services/GeocodingService";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
delete (L.Icon.Default.prototype as any)._getIconUrl;
Expand All @@ -19,10 +26,27 @@ L.Icon.Default.mergeOptions({
});

const LeafletMap = () => {
const dispatch = useAppDispatch();
const controllerComponent = useAppSelector(selectedControllerComponent);

const handleMapClick = async (lat: number, lng: number) => {
if (controllerComponent === "AddCompany") {
const geocodingRes =
await GeocodingService.getReverseGeocodingInfoFromPoint(lng, lat);

geocodingRes
? dispatch(setLocation(geocodingRes))
: dispatch(
setSnackbarText("Didn't find location, try to click building")
);
}
};

const MapEventHandlers = () => {
useMapEvents({
// eslint-disable-next-line no-console
click: (e) => console.log(e),
click: (e) => {
handleMapClick(e.latlng.lat, e.latlng.lng);
},
});
return null;
};
Expand Down

1 comment on commit fcff759

@Jantero93
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.