diff --git a/frontend/cypress/e2e/travelPlanRegister.cy.ts b/frontend/cypress/e2e/travelPlanRegister.cy.ts
index f0397516..c7e04457 100644
--- a/frontend/cypress/e2e/travelPlanRegister.cy.ts
+++ b/frontend/cypress/e2e/travelPlanRegister.cy.ts
@@ -164,7 +164,7 @@ describe("여행 계획 등록 테스트", () => {
// when
cy.get(CYPRESS_SELECTOR_MAP.googleSearchPopup.searchInput).type(INPUT_VALUE);
- cy.get(".pac-item").first().click();
+ cy.get(".pac-item").first().click({ force: true });
// then
cy.get(CYPRESS_SELECTOR_MAP.googleSearchPopup.container).should("not.exist");
diff --git a/frontend/package.json b/frontend/package.json
index 3779bd9a..dd416c06 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -11,7 +11,7 @@
"lint:styled": "stylelint './src/**/*.styled.ts' --fix",
"test": "jest --passWithNoTests",
"test-e2e": "cypress open",
- "test-e2e:run": "cypress run",
+ "test-e2e:run": "cypress run --browser chrome",
"storybook": "storybook dev -p 6006",
"lint": "eslint src/",
"build-storybook": "storybook build"
diff --git a/frontend/src/components/common/Calendar/Calendar.styled.ts b/frontend/src/components/common/Calendar/Calendar.styled.ts
index 48fa6056..64042570 100644
--- a/frontend/src/components/common/Calendar/Calendar.styled.ts
+++ b/frontend/src/components/common/Calendar/Calendar.styled.ts
@@ -68,8 +68,8 @@ export const DayCell = styled.td<{ $isCurrentMonth: boolean; $isSelectable: bool
}
`};
- color: ${({ theme, $isCurrentMonth }) =>
- $isCurrentMonth ? theme.colors.text.secondary : PRIMITIVE_COLORS.gray[300]};
+ color: ${({ theme, $isCurrentMonth, $isSelectable }) =>
+ $isCurrentMonth && $isSelectable ? theme.colors.text.secondary : PRIMITIVE_COLORS.gray[300]};
text-align: center;
`;
diff --git a/frontend/src/components/common/Calendar/Calendar.tsx b/frontend/src/components/common/Calendar/Calendar.tsx
index 6f5a7a67..85d7db80 100644
--- a/frontend/src/components/common/Calendar/Calendar.tsx
+++ b/frontend/src/components/common/Calendar/Calendar.tsx
@@ -75,7 +75,7 @@ const Calendar = ({
onClick={() => isSelectable && onSelectDate(date)}
data-cy={CYPRESS_DATA_MAP.calendar.dayCell}
>
- {date.getDate()}
+ {isCurrentMonth ? date.getDate() : ""}
);
})}
diff --git a/frontend/src/components/common/GoogleMapView/GoogleMapView.constant.ts b/frontend/src/components/common/GoogleMapView/GoogleMapView.constant.ts
new file mode 100644
index 00000000..48b7c322
--- /dev/null
+++ b/frontend/src/components/common/GoogleMapView/GoogleMapView.constant.ts
@@ -0,0 +1,22 @@
+export const GOOGLE_MAP_CONTAINER_STYLE = {
+ width: "100%",
+ height: "23rem",
+};
+
+export const INIT_CENTER_POSITION = {
+ lat: 37.5665,
+ lng: 126.978,
+};
+
+export const GOOGLE_MAP_OPTIONS = {
+ disableDefaultUI: true,
+ styles: [
+ {
+ featureType: "poi",
+ elementType: "labels",
+ stylers: [{ visibility: "off" }],
+ },
+ ],
+};
+
+export const POLYLINE_OPTIONS = { strokeColor: "#72A2FFCC", strokeWeight: 3 };
diff --git a/frontend/src/components/common/GoogleMapView/GoogleMapView.tsx b/frontend/src/components/common/GoogleMapView/GoogleMapView.tsx
index ad018725..79c05c1c 100644
--- a/frontend/src/components/common/GoogleMapView/GoogleMapView.tsx
+++ b/frontend/src/components/common/GoogleMapView/GoogleMapView.tsx
@@ -1,16 +1,20 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import React, { useCallback } from "react";
+import { memo } from "react";
import { GoogleMap, MarkerF, Polyline } from "@react-google-maps/api";
-import theme from "@styles/theme";
+import {
+ GOOGLE_MAP_CONTAINER_STYLE,
+ GOOGLE_MAP_OPTIONS,
+ POLYLINE_OPTIONS,
+} from "@components/common/GoogleMapView/GoogleMapView.constant";
+import {
+ calculateCenter,
+ createMarkerLabelStyle,
+} from "@components/common/GoogleMapView/GoogleMapView.util";
-import { markerUrl } from "@assets/svg";
+import useGoogleMap from "@hooks/useGoogleMap";
-const containerStyle = {
- width: "100%",
- height: "23rem",
-};
+import { markerUrl } from "@assets/svg";
interface GoogleMapViewProps {
places: {
@@ -19,72 +23,43 @@ interface GoogleMapViewProps {
}[];
}
-const calculateCenter = (places: { lat: number; lng: number }[]): { lat: number; lng: number } => {
- const latSum = places.reduce((sum, place) => sum + place.lat, 0);
- const lngSum = places.reduce((sum, place) => sum + place.lng, 0);
- const count = places.length;
-
- return {
- lat: latSum / count,
- lng: lngSum / count,
- };
-};
-
const GoogleMapView = ({ places }: GoogleMapViewProps) => {
const center = calculateCenter(places);
- const onLoad = useCallback(
- (map: google.maps.Map) => {
- const bounds = new window.google.maps.LatLngBounds();
- places.forEach((place) => {
- bounds.extend(new window.google.maps.LatLng(place.lat, place.lng));
- });
- map.fitBounds(bounds);
- },
- [places],
- );
+ const { onLoad, onUnmount, onBoundsChanged } = useGoogleMap(places);
+
+ /**
+ * 컴포넌트 내부에 위치시키지 않으면 "Uncaught TypeError: Cannot read properties of undefined (reading 'maps')"
+ * 에러가 발생하여 다음과 같은 위치로 변경
+ */
+ const MARKER_ICON_STYLE = {
+ url: markerUrl,
+ scaledSize: new window.google.maps.Size(30, 30),
+ labelOrigin: new window.google.maps.Point(15, -10),
+ };
return (
- {places.map((position, index) => (
-
- ))}
{places.map((position, index) => (
))}
-
+
);
};
-export default React.memo(GoogleMapView);
+export default memo(GoogleMapView);
diff --git a/frontend/src/components/common/GoogleMapView/GoogleMapView.util.ts b/frontend/src/components/common/GoogleMapView/GoogleMapView.util.ts
new file mode 100644
index 00000000..e8dc7ced
--- /dev/null
+++ b/frontend/src/components/common/GoogleMapView/GoogleMapView.util.ts
@@ -0,0 +1,27 @@
+import { INIT_CENTER_POSITION } from "@components/common/GoogleMapView/GoogleMapView.constant";
+
+import theme from "@styles/theme";
+
+export const calculateCenter = (
+ places: { lat: number; lng: number }[],
+): { lat: number; lng: number } => {
+ if (places.length === 0) {
+ return { lat: INIT_CENTER_POSITION.lat, lng: INIT_CENTER_POSITION.lng };
+ }
+ const latSum = places.reduce((sum, place) => sum + place.lat, 0);
+ const lngSum = places.reduce((sum, place) => sum + place.lng, 0);
+ const count = places.length;
+
+ return {
+ lat: latSum / count,
+ lng: lngSum / count,
+ };
+};
+
+export const createMarkerLabelStyle = (markerOrder: number) => {
+ return {
+ text: `${markerOrder + 1}`,
+ color: theme.colors.primary,
+ fontSize: "1.4rem",
+ };
+};
diff --git a/frontend/src/components/common/Input/Input.styled.ts b/frontend/src/components/common/Input/Input.styled.ts
index bf5e213a..aa7b4fb7 100644
--- a/frontend/src/components/common/Input/Input.styled.ts
+++ b/frontend/src/components/common/Input/Input.styled.ts
@@ -25,6 +25,7 @@ export const Input = styled.input<{ variant: InputVariants }>`
${({ theme }) => theme.typography.mobile.detail}
color: ${({ theme }) => theme.colors.text.primary};
+ font-size: 1.6rem;
&:disabled {
background-color: ${({ theme }) => theme.colors.background.disabled};
diff --git a/frontend/src/hooks/pages/useTravelPlanDays.ts b/frontend/src/hooks/pages/useTravelPlanDays.ts
index f3f6dbdc..b85a5516 100644
--- a/frontend/src/hooks/pages/useTravelPlanDays.ts
+++ b/frontend/src/hooks/pages/useTravelPlanDays.ts
@@ -124,7 +124,7 @@ export const useTravelPlanDays = (days: TravelTransformPlaces[]) => {
const travelPlanPlace = previousTravelPlanDays[dayIndex]?.places[placeIndex];
if (travelPlanPlace?.todos) {
- travelPlanPlace.todos.splice(Number(todoId), 1);
+ travelPlanPlace.todos = travelPlanPlace.todos.filter((todo) => todo.id !== todoId);
}
});
},
diff --git a/frontend/src/hooks/useGoogleMap.ts b/frontend/src/hooks/useGoogleMap.ts
new file mode 100644
index 00000000..56d049d4
--- /dev/null
+++ b/frontend/src/hooks/useGoogleMap.ts
@@ -0,0 +1,43 @@
+import { useCallback, useState } from "react";
+
+import { MapPosition } from "@type/domain/common";
+
+const INIT_CENTER_POSITION = {
+ lat: 37.5665,
+ lng: 126.978,
+};
+
+const useGoogleMap = (places: MapPosition[]) => {
+ const [googleMap, setGoogleMap] = useState(null);
+
+ const onLoad = useCallback((map: google.maps.Map) => {
+ setGoogleMap(map);
+ }, []);
+
+ const onUnmount = useCallback(() => {
+ setGoogleMap(null);
+ }, []);
+
+ const onBoundsChanged = useCallback(() => {
+ if (googleMap) {
+ if (places.length === 0) {
+ googleMap.setCenter(INIT_CENTER_POSITION);
+ googleMap.setZoom(7);
+ } else {
+ const bounds = new window.google.maps.LatLngBounds();
+ places.forEach((place) => {
+ bounds.extend(new window.google.maps.LatLng(place.lat, place.lng));
+ });
+ googleMap.fitBounds(bounds);
+ }
+ }
+ }, [places, googleMap]);
+
+ return {
+ onLoad,
+ onUnmount,
+ onBoundsChanged,
+ };
+};
+
+export default useGoogleMap;
diff --git a/frontend/webpack.common.js b/frontend/webpack.common.js
index 904b799a..35dae068 100644
--- a/frontend/webpack.common.js
+++ b/frontend/webpack.common.js
@@ -45,8 +45,18 @@ module.exports = {
use: ["@svgr/webpack"],
},
{
- test: /\.(png|jpg|jpeg|gif|woff|webp)$/i,
+ test: /\.(png|jpg|jpeg|gif|webp|avif)$/i,
type: "asset/resource",
+ generator: {
+ filename: "assets/images/[name].[contenthash:8][ext]",
+ },
+ },
+ {
+ test: /\.(woff)$/i,
+ type: "asset/resource",
+ generator: {
+ filename: "assets/fonts/[name].[contenthash:8][ext]",
+ },
},
{
test: /\.(ts|tsx)$/i,
diff --git a/frontend/webpack.production.js b/frontend/webpack.production.js
index a373be4d..bb0581b0 100644
--- a/frontend/webpack.production.js
+++ b/frontend/webpack.production.js
@@ -4,11 +4,17 @@ const common = require("./webpack.common");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const dotenv = require("dotenv");
// const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
+const path = require("path");
const env = dotenv.config({ path: ".env.production" }).parsed;
module.exports = merge(common, {
mode: "production",
+ output: {
+ publicPath: "/",
+ filename: "[name].[contenthash:8].js",
+ path: path.resolve(__dirname, "dist"),
+ },
devtool: "hidden-source-map",
cache: {
type: "filesystem",
@@ -31,4 +37,9 @@ module.exports = merge(common, {
// openAnalyzer: true,
// }),
],
+ optimization: {
+ splitChunks: {
+ chunks: "all",
+ },
+ },
});