Skip to content

Commit

Permalink
Merge pull request #602 from isucon/fix-simulator-code
Browse files Browse the repository at this point in the history
[FE] Simulator画面部分のコードのリファクタ
  • Loading branch information
narirou authored Dec 4, 2024
2 parents 2f5261e + 628b0cf commit 924af01
Show file tree
Hide file tree
Showing 13 changed files with 241 additions and 187 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const currentCoodinatePost = (coordinate: Coordinate) => {
});
}
};

const postEnroute = (chair: SimulatorChair, coordinate: Coordinate) => {
if (chair.chairNotification?.payload?.ride_id) {
setSimulatorStartCoordinate(coordinate);
Expand All @@ -68,6 +69,7 @@ const postCarring = (chair: SimulatorChair) => {
}).catch((e) => console.error(e));
}
};

export const useEmulator = (targetChair?: SimulatorChair) => {
useEffect(() => {
if (
Expand Down
8 changes: 3 additions & 5 deletions frontend/app/components/hooks/use-ghost-chairs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useEffect, useState } from "react";
import { NearByChair } from "~/types";
import { Message, MessageTypes } from "~/utils/post-message";
import { TownList } from "../modules/map/map-data";

const randomInt = (min: number, max: number) =>
Expand Down Expand Up @@ -47,12 +48,9 @@ export const useGhostChairs = (): NearByChair[] => {
const onMessage = ({
origin,
data,
}: MessageEvent<{
type: "isuride.simulator.config";
payload?: { ghostChairEnabled?: boolean };
}>) => {
}: MessageEvent<Message["SimulatorConfing"]>) => {
const isSameOrigin = origin == location.origin;
if (isSameOrigin && data.type === "isuride.simulator.config") {
if (isSameOrigin && MessageTypes.SimulatorConfing === data.type) {
setEnabled(data?.payload?.ghostChairEnabled ?? false);
}
};
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/components/modules/map/map-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type Town = {
name: string;
image: Image;
centerCoordinate: Coordinate;
color: string;
color: `#${string}`;
};

const CityObjectImages = [
Expand Down
3 changes: 1 addition & 2 deletions frontend/app/components/modules/map/map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -282,13 +282,12 @@ const TownLayer = memo(function TownLayer() {
>
<div
role="presentation"
className="absolute rounded-full bg-neutral-100 bg-opacity-40 border-4 border-neutral-200"
className="absolute rounded-full bg-neutral-300 bg-opacity-40"
style={{
width: image.width + 20,
height: image.width + 20,
top: -10,
left: -10,
borderColor: color,
}}
></div>
<img
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
import { ComponentProps, FC } from "react";
import { twMerge } from "tailwind-merge";
import colors from "tailwindcss/colors";
import { RideStatus } from "~/api/api-schemas";
import { Text } from "~/components/primitives/text/text";

const StatusList = {
MATCHING: ["空車", "text-sky-500"],
ENROUTE: ["迎車", "text-amber-500"],
PICKUP: ["乗車待ち", "text-amber-500"],
CARRYING: ["賃走", "text-red-500"],
ARRIVED: ["到着", "text-emerald-500"],
COMPLETED: ["完了", "text-emerald-500"],
MATCHING: ["空車", colors.sky["500"]],
ENROUTE: ["迎車", colors.amber["500"]],
PICKUP: ["乗車待ち", colors.amber["500"]],
CARRYING: ["賃走", colors.red["500"]],
ARRIVED: ["到着", colors.emerald["500"]],
COMPLETED: ["完了", colors.emerald["500"]],
} as const;

export const SimulatorChairRideStatus: FC<
ComponentProps<"div"> & {
currentStatus: RideStatus;
}
> = ({ currentStatus, className, ...props }) => {
const [labelName, colorClass] = StatusList[currentStatus];
const [labelName, color] = StatusList[currentStatus];
return (
<div className={twMerge("font-bold", colorClass, className)} {...props}>
<Text className="before:content-['●'] before:mr-1.5" size="sm">
<div
className={twMerge("font-bold flex items-center space-x-1", className)}
{...props}
>
<div
role="presentation"
className="w-3 h-3 rounded-full"
style={{ backgroundColor: color }}
/>
<Text size="sm" style={{ color }}>
{labelName}
</Text>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
import { FC, memo, useCallback, useMemo, useRef, useState } from "react";
import { twMerge } from "tailwind-merge";
import colors from "tailwindcss/colors";
import { fetchChairPostActivity } from "~/api/api-components";
import { RideStatus } from "~/api/api-schemas";
import { useEmulator } from "~/components/hooks/use-emulate";
import { ChairIcon } from "~/components/icon/chair";
import { PinIcon } from "~/components/icon/pin";
import { LocationButton } from "~/components/modules/location-button/location-button";
import { Map } from "~/components/modules/map/map";
import { Button } from "~/components/primitives/button/button";
import { Toggle } from "~/components/primitives/form/toggle";
import { Modal } from "~/components/primitives/modal/modal";
import { Text } from "~/components/primitives/text/text";
import { useSimulatorContext } from "~/contexts/simulator-context";
import { Coordinate, SimulatorChair } from "~/types";
import { isArrayIncludes } from "~/utils/includes";
import { SimulatorChairRideStatus } from "../simulator-chair-status/simulator-chair-status";
import { getSimulatorStartCoordinate } from "~/utils/storage";
import { twMerge } from "tailwind-merge";
import { SimulatorChairRideStatus } from "../simulator-chair-status/simulator-chair-status";

const CoordinatePickup: FC<{
coordinateState: SimulatorChair["coordinateState"];
Expand Down Expand Up @@ -80,93 +76,87 @@ const CoordinatePickup: FC<{
);
};

const SimulatorProgress: FC<{
const progress = (
start: Coordinate,
current: Coordinate,
end: Coordinate,
): number => {
const distance =
Math.abs(end.latitude - start.latitude) +
Math.abs(end.longitude - start.longitude);
const progress =
Math.abs(end.latitude - current.latitude) +
Math.abs(end.longitude - current.longitude);
return Math.floor(((distance - progress) / distance) * 100);
};

const ChairProgress: FC<{
model: string;
rideStatus: RideStatus | undefined;
current: Coordinate | undefined;
pickup?: Coordinate;
destlocation?: Coordinate;
}> = ({ model, rideStatus, pickup, destlocation, current }) => {
const startCoordinate = useMemo(() => {
currentLoc: Coordinate | undefined;
pickupLoc?: Coordinate;
destLoc?: Coordinate;
}> = ({ model, rideStatus, pickupLoc, destLoc, currentLoc }) => {
const startLoc = useMemo(() => {
return rideStatus !== undefined ? getSimulatorStartCoordinate() : null;
}, [rideStatus]);

const pickupProgress: number = useMemo(() => {
if (
rideStatus === "MATCHING" ||
!rideStatus ||
!pickup ||
!startCoordinate ||
!current
)
if (!rideStatus || !pickupLoc || !startLoc || !currentLoc) {
return 0;
if (
rideStatus === "PICKUP" ||
rideStatus === "ARRIVED" ||
rideStatus === "CARRYING" ||
rideStatus === "COMPLETED"
)
return 100;
const distance =
Math.abs(pickup?.latitude - startCoordinate.latitude) +
Math.abs(pickup?.longitude - startCoordinate.longitude);
const progress =
Math.abs(pickup?.latitude - current?.latitude) +
Math.abs(pickup?.longitude - current.longitude);
return Math.floor(((distance - progress) / distance) * 100);
}, [rideStatus, pickup, current, startCoordinate]);
}
switch (rideStatus) {
case "MATCHING":
return 0;
case "PICKUP":
case "ARRIVED":
case "CARRYING":
case "COMPLETED":
return 100;
default:
return progress(startLoc, currentLoc, pickupLoc);
}
}, [rideStatus, pickupLoc, startLoc, currentLoc]);

const distanceProgress: number = useMemo(() => {
if (
rideStatus === "MATCHING" ||
rideStatus === "PICKUP" ||
rideStatus === "ENROUTE" ||
!rideStatus ||
!destlocation ||
!pickup ||
!current
)
if (!rideStatus || !destLoc || !pickupLoc || !currentLoc) {
return 0;
if (rideStatus === "ARRIVED" || rideStatus === "COMPLETED") return 100;
const distance =
Math.abs(destlocation?.latitude - pickup.latitude) +
Math.abs(destlocation?.longitude - pickup.longitude);
const progress =
Math.abs(destlocation?.latitude - current.latitude) +
Math.abs(destlocation?.longitude - current.longitude);
return Math.floor(((distance - progress) / distance) * 100);
}, [rideStatus, pickup, destlocation, current]);
}
switch (rideStatus) {
case "MATCHING":
case "PICKUP":
case "ENROUTE":
return 0;
case "ARRIVED":
case "COMPLETED":
return 100;
default:
return progress(destLoc, currentLoc, pickupLoc);
}
}, [rideStatus, destLoc, pickupLoc, currentLoc]);

return (
<div className="flex items-center mt-8">
<div className="flex border-b ms-6 pb-1 w-full">
<div className="flex items-center">
<div className="flex border-b pb-1 w-full">
<div className="flex w-1/2">
<PinIcon color={colors.red[500]} width={20} height={20} />
<PinIcon color={colors.red[500]} width={20} />
<div className="relative w-full ms-6">
{isArrayIncludes(
[
"PICKUP",
"CARRYING",
"ARRIVED",
"COMPLETED",
] as const satisfies RideStatus[],
rideStatus,
) && (
<ChairIcon
model={model}
className={`size-6 absolute top-[-2px] ${rideStatus === "CARRYING" ? "animate-shake" : ""}`}
style={{ right: `${distanceProgress}%` }}
/>
)}
{rideStatus &&
["PICKUP", "CARRYING", "ARRIVED", "COMPLETED"].includes(
rideStatus,
) && (
<ChairIcon
model={model}
className={`size-6 absolute top-[-2px] ${rideStatus === "CARRYING" ? "animate-shake" : ""}`}
style={{ right: `${distanceProgress}%` }}
/>
)}
</div>
</div>
<div className="flex w-1/2">
<PinIcon color={colors.black} width={20} height={20} />
<PinIcon color={colors.black} width={20} />
<div className="relative w-full ms-6">
{isArrayIncludes(
["MATCHING", "ENROUTE"] as const satisfies RideStatus[],
rideStatus,
) && (
{rideStatus && ["MATCHING", "ENROUTE"].includes(rideStatus) && (
<ChairIcon
model={model}
className={twMerge(
Expand All @@ -182,29 +172,14 @@ const SimulatorProgress: FC<{
</div>
);
};

export const SimulatorChairDisplay: FC = () => {
const { targetChair: chair } = useSimulatorContext();
const [activate, setActivate] = useState<boolean>(true);

const toggleActivate = useCallback(
(activity: boolean) => {
try {
void fetchChairPostActivity({ body: { is_active: activity } });
setActivate(activity);
} catch (error) {
console.error(error);
}
},
[setActivate],
);

const rideStatus = useMemo(
() => chair?.chairNotification?.status ?? "MATCHING",
[chair],
);

useEmulator(chair);

const ChairDetailInfo = memo(
function ChairDetailInfo({
chairModel,
Expand Down Expand Up @@ -233,46 +208,28 @@ export const SimulatorChairDisplay: FC = () => {
);

return (
<>
<div className="bg-white rounded shadow px-6 py-4 w-full">
{chair ? (
<div className="space-y-4">
<ChairDetailInfo
chairModel={chair.model}
chairName={chair.name}
rideStatus={rideStatus}
/>
<CoordinatePickup coordinateState={chair.coordinateState} />
<SimulatorProgress
model={chair.model}
rideStatus={rideStatus}
current={chair.coordinateState.coordinate}
pickup={chair.chairNotification?.payload?.coordinate?.pickup}
destlocation={
chair.chairNotification?.payload?.coordinate?.destination
}
/>
</div>
) : (
<Text className="m-4" size="sm">
椅子のデータがありません
</Text>
)}
</div>
{chair && (
<div className="bg-white rounded shadow px-6 py-4 w-full">
<div className="flex justify-between items-center">
<Text size="sm" className="text-neutral-500" bold>
配車を受け付ける
</Text>
<Toggle
checked={activate}
onUpdate={(v) => toggleActivate(v)}
id="chair-activity"
/>
</div>
<div className="bg-white rounded shadow px-6 py-4 w-full">
{chair ? (
<div className="space-y-4">
<ChairDetailInfo
chairModel={chair.model}
chairName={chair.name}
rideStatus={rideStatus}
/>
<CoordinatePickup coordinateState={chair.coordinateState} />
<ChairProgress
model={chair.model}
rideStatus={rideStatus}
currentLoc={chair.coordinateState.coordinate}
pickupLoc={chair.chairNotification?.payload?.coordinate?.pickup}
destLoc={chair.chairNotification?.payload?.coordinate?.destination}
/>
</div>
) : (
<Text className="m-4" size="sm">
椅子のデータがありません
</Text>
)}
</>
</div>
);
};
Loading

0 comments on commit 924af01

Please sign in to comment.