Skip to content

Commit

Permalink
Merge floors and rooms fetch (#22)
Browse files Browse the repository at this point in the history
* Merged floors and rooms fetch request

* Removed state from rooms slice

* Room id is number

* Floor id is number

* Updated readme
  • Loading branch information
Daniil Ryzhkov authored Oct 2, 2022
1 parent 5b57d51 commit e480db7
Show file tree
Hide file tree
Showing 21 changed files with 156 additions and 209 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ A client side part of a web app for managing hotel bookings by organazing them i
- **React Router**: single page app routing.

## Changes
### v1.1.1
- Merged floors and rooms GET API method endpoints.
### v1.1.0
- Added hotel edit page.
- Splitted hotel API endpoint into two: floors and rooms.
Expand Down
19 changes: 8 additions & 11 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,16 @@ export type ClientData = {
};

export type Room = {
id: string,
floorId: string,
id: number,
floorId: number,
number: string,
type: string
};

export type Floor = {
id: string,
id: number,
name: string,
rooms: Room[]
};

export type RoomType = {
Expand All @@ -55,31 +56,27 @@ export function fetchFloorsAsync(): Promise<{ data: Floor[] }> {
return fetchJsonDataAsync<Floor[]>("/api/v1/floors");
}

export function postFloorAsync(floor: { name: string }): Promise<{ id: string }> {
export function postFloorAsync(floor: { name: string }): Promise<{ id: number }> {
return postDataAsync("/api/v1/floors", floor);
}

export function putFloorAsync(floor: Floor): Promise<void> {
return putDataAsync(`api/v1/floors/${floor.id}`, floor);
}

export function deleteFloorAsync(id: string): Promise<void> {
export function deleteFloorAsync(id: number): Promise<void> {
return deleteDataAsync(`api/v1/floors/${id}`);
}

export function fetchRoomsAsync(): Promise<{ data: Room[] }> {
return fetchJsonDataAsync<Room[]>("/api/v1/rooms");
}

export function postRoomAsync(room: { floorId: string, number: string, type: string }): Promise<{ id: string }> {
export function postRoomAsync(room: { floorId: number, number: string, type: string }): Promise<{ id: number }> {
return postDataAsync("api/v1/rooms", room);
}

export function putRoomAsync(room: Room): Promise<void> {
return putDataAsync(`api/v1/rooms/${room.id}`, room);
}

export function deleteRoomAsync(id: string): Promise<void> {
export function deleteRoomAsync(id: number): Promise<void> {
return deleteDataAsync(`api/v1/rooms/${id}`);
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/ExpandableTile/Details/Error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type ErrorWrappeeProps = {

function ErrorWrappee({ tile }: ErrorWrappeeProps): JSX.Element | null {
const errorType: "none" | "warning" | "error" = useAppSelector((state) => {
if (!tile.roomId) {
if (tile.roomId === undefined) {
return "none";
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/ExpandableTile/Header/RoomNumber.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useAppSelector } from "../../../redux/hooks";

export default function RoomNumber(): JSX.Element | null {
const { data } = useContext(TileContext);
const roomNumber = useAppSelector((state) => data && data.roomId ? state.rooms.data[data.roomId].number : undefined);
const roomNumber = useAppSelector((state) => data && data.roomId !== undefined ? state.rooms.data[data.roomId].number : undefined);

if (data && roomNumber) {
return (
Expand Down
4 changes: 2 additions & 2 deletions src/components/Settings/Floor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import M3Dialog from "../m3/M3Dialog";
import M3TextButton from "../m3/M3TextButton";

type FloorProps = {
id: string,
id: number,
floor: FloorData
};

Expand Down Expand Up @@ -63,7 +63,7 @@ export default function Floor({ id, floor }: FloorProps): JSX.Element {
function edit(): void {
async function putAsync(): Promise<void> {
try {
const newFloor: FloorDTO = { id, name };
const newFloor: FloorDTO = { id, name, rooms: [] };
await putFloorAsync(newFloor);
dispatch(editFloor(newFloor));
} catch (error) {
Expand Down
4 changes: 2 additions & 2 deletions src/components/Settings/Room.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import M3Dialog from "../m3/M3Dialog";
import M3TextButton from "../m3/M3TextButton";

type RoomProps = {
id: string,
floorId: string
id: number,
floorId: number
};

export default function Room({ id, floorId }: RoomProps): JSX.Element {
Expand Down
7 changes: 1 addition & 6 deletions src/components/Settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import Typography from "@mui/material/Typography";

import { useAppDispatch, useAppSelector, useFloors } from "../../redux/hooks";
import { fetchAsync as fetchFloorsAsync } from "../../redux/floorsSlice";
import { fetchAsync as fetchRoomsAsync } from "../../redux/roomsSlice";

import DrawerAdjacent from "../m3/DrawerAdjacent";
import CreateFloorDialog from "./CreateFloorDialog";
Expand All @@ -16,16 +15,12 @@ export default function Settings(): JSX.Element {
const floors = useFloors();
const floorsReady = useAppSelector((state) => state.floors.status === "idle");

const floorIds = Object.keys(floors);
const floorIds = Object.keys(floors).map(Number);

useEffect(() => {
dispatch(fetchFloorsAsync());
}, [dispatch]);

useEffect(() => {
dispatch(fetchRoomsAsync());
}, [dispatch]);

return (
<DrawerAdjacent>
<Stack spacing={2} sx={{ pr: "1rem", pb: "1rem" }}>
Expand Down
11 changes: 0 additions & 11 deletions src/components/Table/FetchData/FetchRoomsData.tsx

This file was deleted.

4 changes: 1 addition & 3 deletions src/components/Table/FetchData/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import React from "react";

import FetchFloorsData from "./FetchFloorsData";
import FetchRoomsData from "./FetchRoomsData";
import FetchRoomTypes from "./FetchRoomTypes";
import FetchTiles from "./FetchTiles";

export default function FetchData(): JSX.Element {
return (
<>
<FetchFloorsData />
<FetchRoomsData />
<FetchRoomTypes />
<FetchFloorsData />
<FetchTiles />
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import FreeSpace from "./FreeSpace";
import DropZone from "./DropZone";

type DateCellSwitchProps = {
roomId: string,
roomId: number,
date: string
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { move } from "../../../../../../../../redux/tilesSlice";

type DropAccepterProps = {
children: React.ReactNode,
roomId: string
roomId: number
};

export default function DropAccepter({ children, roomId }: DropAccepterProps): JSX.Element {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Size from "../../../../../../../Tile/Size";
import DropAccepter from "./DropAccepter";

type DropZoneProps = {
roomId: string,
roomId: number,
data: TileData
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import DateCellSwitch from "./DateCellSwitch";

type DataRowProps = {
isFirst: boolean,
roomId: string
roomId: number
}

export default function DataRow({ isFirst, roomId }: DataRowProps): JSX.Element {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Table/Section/Floor/Room/Body/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import RowBody from "../../../Row/Body";
type BodyProps = {
isFirst: boolean,
isLast: boolean,
roomId: string
roomId: number
}

export default function Body({ isFirst, isLast, roomId }: BodyProps): JSX.Element {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Table/Section/Floor/Room/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Body from "./Body";
import Header from "./Header";

type RoomProps = {
id: string,
id: number,
isFirst: boolean,
isLast: boolean
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/Table/Sections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Skeleton from "./Skeleton";
export default function Sections(): JSX.Element {
const theme = useTheme();
const floors = useFloors();
const floorIds = Object.keys(floors);
const floorIds = Object.keys(floors).map(Number);

return (
<Stack spacing={0} sx={{
Expand Down
2 changes: 1 addition & 1 deletion src/components/Tile/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type AlertWrappeeProps = {

function AlertWrappee({ children, data }: AlertWrappeeProps): JSX.Element {
const { cropRight } = useContext(TileContext);
const assignedRoomType = useAppSelector((state) => data.roomId ? state.rooms.data[data.roomId].type : undefined);
const assignedRoomType = useAppSelector((state) => data.roomId !== undefined ? state.rooms.data[data.roomId].type : undefined);
const occupancy = useAppSelector((state) => assignedRoomType ? state.roomTypes.data[assignedRoomType] : undefined);
const badgeColor = useBadgeColor(data, occupancy, assignedRoomType);

Expand Down
30 changes: 8 additions & 22 deletions src/redux/floorsSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit";

import { fetchFloorsAsync } from "../api";
import { show as showMessage } from "./snackbarMessageSlice";
import { fetchAsync as fetchRoomsAsync } from "./roomsSlice";

export type Floor = {
name: string,
roomIds: string[]
roomIds: number[]
};

export type Floors = {
[key: string]: Floor
[key: number]: Floor
};

export type State = {
Expand Down Expand Up @@ -42,29 +41,29 @@ export const floorsSlice = createSlice({
name: "floors",
initialState: initialState,
reducers: {
createFloor: (state, action: PayloadAction<{ id: string, name: string }>) => {
createFloor: (state, action: PayloadAction<{ id: number, name: string }>) => {
const floor = action.payload;
state.data[floor.id] = { name: floor.name, roomIds: [ ]};
},
editFloor: (state, action: PayloadAction<{ id: string, name: string }>) => {
editFloor: (state, action: PayloadAction<{ id: number, name: string }>) => {
const floor = action.payload;
if (state.data[floor.id]) {
state.data[floor.id].name = floor.name;
}
},
deleteFloor: (state, action: PayloadAction<string>) => {
deleteFloor: (state, action: PayloadAction<number>) => {
if (state.data[action.payload]) {
delete state.data[action.payload];
}
},
createRoom: (state, action: PayloadAction<{ floorId: string, roomId: string }>) => {
createRoom: (state, action: PayloadAction<{ floorId: number, roomId: number }>) => {
const room = action.payload;
const floor = state.data[room.floorId];
if (floor) {
floor.roomIds.push(room.roomId);
}
},
deleteRoom: (state, action: PayloadAction<{ floorId: string, roomId: string }>) => {
deleteRoom: (state, action: PayloadAction<{ floorId: number, roomId: number }>) => {
const room = action.payload;
const floor = state.data[room.floorId];
if (floor) {
Expand All @@ -85,24 +84,11 @@ export const floorsSlice = createSlice({
state.status = "idle";
const data = action.payload;
for (const floor of data) {
if (!state.data[floor.id]) {
state.data[floor.id] = { name: floor.name, roomIds: [] };
} else {
state.data[floor.id].name = floor.name;
}
state.data[floor.id] = { name: floor.name, roomIds: floor.rooms.map((room) => room.id) };
}
})
.addCase(fetchAsync.rejected, (state) => {
state.status = "failed";
})
.addCase(fetchRoomsAsync.fulfilled, (state, action) => {
const rooms = action.payload;
for (const room of rooms) {
if (!state.data[room.floorId]) {
state.data[room.floorId] = { name: "", roomIds: [] };
}
state.data[room.floorId].roomIds.push(room.id);
}
});
}
});
Expand Down
43 changes: 12 additions & 31 deletions src/redux/roomsSlice.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,31 @@
import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit";
import { fetchRoomsAsync } from "../api";
import { show as showMessage } from "./snackbarMessageSlice";
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { fetchAsync as fetchFloorsAsync } from "./floorsSlice";

export type Room = {
number: string,
type: string
};

export type Rooms = {
[key: string]: Room
[key: number]: Room
};

export type State = {
data: Rooms,
status: "idle" | "loading" | "failed"
};

const initialState: State = {
data: { },
status: "idle"
};

export const fetchAsync = createAsyncThunk(
"rooms/fetch",
async (_, thunkApi) => {
try {
const response = await fetchRoomsAsync();
return response.data;
} catch (error) {
thunkApi.dispatch(showMessage({ type: "error" }));
throw thunkApi.rejectWithValue([]);
}
}
);

export const roomsSlice = createSlice({
name: "rooms",
initialState: initialState,
reducers: {
setRoom: (state, action: PayloadAction<{ id: string, room: Room}>) => {
setRoom: (state, action: PayloadAction<{ id: number, room: Room}>) => {
state.data[action.payload.id] = action.payload.room;
},
deleteRooms: (state, action: PayloadAction<{ ids: string[] }>) => {
deleteRooms: (state, action: PayloadAction<{ ids: number[] }>) => {
const rooms = action.payload.ids;
for (const roomId of rooms) {
if (state.data[roomId]) {
Expand All @@ -52,19 +36,16 @@ export const roomsSlice = createSlice({
},
extraReducers: (builder) => {
builder
.addCase(fetchAsync.pending, (state) => {
state.status = "loading";
.addCase(fetchFloorsAsync.pending, (state) => {
state.data = { };
})
.addCase(fetchAsync.fulfilled, (state, action) => {
state.status = "idle";
const rooms = action.payload;
for (const room of rooms) {
state.data[room.id] = { number: room.number, type: room.type };
.addCase(fetchFloorsAsync.fulfilled, (state, action) => {
const floors = action.payload;
for (const floor of floors) {
for (const room of floor.rooms) {
state.data[room.id] = { number: room.number, type: room.type };
}
}
})
.addCase(fetchAsync.rejected, (state) => {
state.status = "failed";
});
}
});
Expand Down
Loading

0 comments on commit e480db7

Please sign in to comment.