Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/30 non member add profile api #35

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions fe/src/app/api/nonmembers/pings/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const uuid = searchParams.get("uuid");

if (!uuid) {
return NextResponse.json(
{ error: "UUID parameter is missing" },
{ status: 400 }
);
}

try {
// 외부 API 요청 보내기
const externalResponse = await fetch(`/api/nonmembers/pings?uuid=${uuid}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});

// 외부 API 요청 실패 처리
if (!externalResponse.ok) {
return NextResponse.json(
{ error: "Failed to fetch data from external API" },
{ status: externalResponse.status }
);
}

// JSON 데이터로 변환
const data = await externalResponse.json();

// 외부 API에서 받은 데이터를 클라이언트로 반환
return NextResponse.json(data, { status: 200 });
} catch (error) {
// 오류 처리
console.error("Error fetching data:", error);
return NextResponse.json(
{ error: "Internal Server Error" },
{ status: 500 }
);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import React, { useState } from "react";
import Image from "next/image";
import { useLocationStore } from "../stores/useLocationStore";
import useDataStore from "../stores/useDataStore";

export default function BottomDrawer() {
const [selectedButton, setSelectedButton] = useState<number | null>(null);
const moveToLocation = useLocationStore((state) => state.moveToLocation);

const nonMembers = useDataStore((state) => state.data?.nonMembers || []);
console.log(nonMembers);
const handleLocationClick = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
Expand Down Expand Up @@ -35,15 +38,6 @@ export default function BottomDrawer() {
}
};

const buttons = [
{ label: "메롱메롱", id: 1 },
{ label: "메롱메롱", id: 2 },
{ label: "메롱메롱", id: 3 },
{ label: "메윤소민", id: 4 },
{ label: "메롱윤소민", id: 5 },
{ label: "메롱윤소민", id: 6 },
];

return (
<div className="w-full h-[218px] bg-grayscale-90 z-10 rounded-t-xlarge">
<div className="absolute mr-[16px] right-0 -top-[120px] flex flex-col">
Expand Down Expand Up @@ -99,23 +93,23 @@ export default function BottomDrawer() {
<Image src="/svg/add.svg" alt="add" width={68} height={68} />
</button>
</div>
{buttons.map((button) => (
{nonMembers.map((member) => (
<div
key={button.id}
key={member.nonMemberId}
className="w-[68px] h-[90px] flex flex-col justify-between shrink-0"
>
<button
type="button"
onClick={() => handleButtonClick(button.id)}
onClick={() => handleButtonClick(member.nonMemberId)}
className={`w-[68px] h-[68px] ${
selectedButton === button.id
selectedButton === member.nonMemberId
? "border-2 rounded-lg border-primary-50"
: ""
}`}
>
<Image src="/svg/add.svg" alt="add" width={68} height={68} />
</button>
<div className="text-center">{button.label}</div>
<div className="text-center">{member.name}</div>
</div>
))}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,58 @@ import NameField from "./NameField";
import PinField from "./PinField";
import LinkField from "./LinkField";

export default function Form() {
interface FormProps {
uuid: string;
}

export default function Form({ uuid }: FormProps) {
const [name, setName] = useState("");
const [pin, setPin] = useState(["", "", "", ""]);
const [mapLinks, setMapLinks] = useState([""]);
const [storeLinks, setStoreLinks] = useState([""]);
const [isFormComplete, setIsFormComplete] = useState(false);
const [isTooltipVisible, setIsTooltipVisible] = useState(true);

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();

const requestBody = {
uuid,
name,
password: pin.join(""),
bookmarkUrls: mapLinks,
storeUrls: storeLinks,
};

console.log("Request Body:", JSON.stringify(requestBody, null, 2));

try {
const response = await fetch(
"http://110.165.17.236:8081/api/v1/nonmembers/pings",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(requestBody),
}
);

// 요청 성공 여부 확인
if (response.ok) {
console.log("요청에 성공했습니다. 상태 코드:", response.status);
} else {
console.log("요청에 실패했습니다. 상태 코드:", response.status);
}
} catch (error) {
console.log("서버 오류가 발생했습니다.", error);
}
};

useEffect(() => {
const isPinComplete = pin.every((digit) => digit !== "");
const hasMapLink = mapLinks.some((link) => link !== "");
const hasStoreLink = storeLinks.some((link) => link !== "");
setIsFormComplete(!!(name && isPinComplete && hasMapLink && hasStoreLink));
}, [name, pin, mapLinks, storeLinks]);
setIsFormComplete(!!(name && isPinComplete));
}, [name, pin]);

useEffect(() => {
const hideTooltip = (e: MouseEvent) => {
Expand All @@ -38,10 +76,9 @@ export default function Form() {

return (
<div className="px-4">
<form>
<form onSubmit={handleSubmit}>
<NameField value={name} onChange={setName} />
<PinField value={pin} onChange={setPin} />

<LinkField
label="맵핀 모음 링크"
placeholder="링크 붙여넣기"
Expand All @@ -50,14 +87,12 @@ export default function Form() {
showTooltip={isTooltipVisible}
onInfoClick={() => setIsTooltipVisible(true)}
/>

<LinkField
label="가게 정보 링크"
placeholder="링크 붙여넣기"
value={storeLinks}
onChange={setStoreLinks}
/>

<button
className={`w-full flex items-center text-lg font-200 justify-center h-[60px] rounded-small ${
isFormComplete
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ export default function LinkField({
const [inputFields, setInputFields] = useState(
value.map((val) => ({ id: nanoid(), text: val }))
);

const handleNaverMove = () => {
window.open("https://m.place.naver.com/my/place");
};
const handleInputChange = (id: string, inputValue: string) => {
const newInputs = inputFields.map((field) =>
field.id === id ? { ...field, text: inputValue } : field
Expand Down Expand Up @@ -76,6 +78,19 @@ export default function LinkField({
)}
</div>
)}
<button
type="button"
className="mr-0 ml-auto text-grayscale-50 flex items-center text-text-sm1"
onClick={handleNaverMove}
>
네이버 지도
<Image
src="/svg/rightArrow.svg"
alt="rightArrow"
width={12}
height={24}
/>
</button>
</label>
<div className="flex flex-col items-center border-grayscale-10 border p-[16px] gap-[16px] rounded-medium">
{inputFields.map((field) => (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
"use client";

import Image from "next/image";
import { useParams } from "next/navigation";
import Form from "./components/Form";

export default function Page() {
const { id } = useParams();
const uuid = Array.isArray(id) ? id[0] : id;

return (
<div className="w-full h-screen flex justify-center items-center">
<div className="max-w-[360px] w-full h-screen overflow-y-auto hide-scrollbar">
Expand All @@ -20,9 +24,14 @@ export default function Page() {
<div className="mt-[24px] mb-[44px] ml-[16px] text-darkGray text-title-md">
저장해둔 맵핀을 불러올게요
</div>
<Form />
<Form uuid={uuid} />
<div className="h-[20px]" />
</div>
<div className="mt-[24px] mb-[44px] ml-[16px] text-darkGray text-title-md">
저장해둔 맵핀을 불러올게요
</div>
<Form uuid={uuid} />
<div className="h-[20px]" />
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,53 @@
"use client";

import React from "react";
import React, { useEffect } from "react";
import { useParams } from "next/navigation";
import useDataStore from "./stores/useDataStore";
import MapComponent from "./components/MapComponent";
import BottomDrawer from "./components/BottomDrawer";
import useDrawer from "./hooks/useDrawer";
import Image from "next/image";
import { a } from "@react-spring/web";
import { useDrag } from "@use-gesture/react";
import BottomDrawer from "./components/BottomDrawer";
import MapComponent from "./components/MapComponent";
import useDrawer from "./hooks/useDrawer";

export default function Page() {
const { y, openDrawer, closeDrawer, setPosition } = useDrawer();
const { id } = useParams();
const setData = useDataStore((state) => state.setData);
const data = useDataStore((state) => state.data);

useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(
`http://110.165.17.236:8081/api/v1/nonmembers/pings?uuid=${id}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
);

if (response.ok) {
const result = await response.json();
if (!data) {
setData(result);
console.log("Response Data:", JSON.stringify(result, null, 2));
}
} else {
console.error("데이터 가져오기에 실패했습니다.");
}
} catch (error) {
console.error("서버 오류:", error);
}
};

// data가 비어있을 때 fetchData 호출
if (!data) {
fetchData();
}
}, []);

const bind = useDrag(
({ last, movement: [, my], memo = y.get() }) => {
Expand Down
29 changes: 29 additions & 0 deletions fe/src/app/event-maps/[id]/stores/useDataStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { create } from "zustand";

// 데이터 형식을 정의
interface NonMember {
nonMemberId: number;
name: string;
}

interface Data {
uuid: string;
name: string;
password: string;
bookmarkUrls: string[];
storeUrls: string[];
nonMembers: NonMember[]; // nonMembers 추가
}

// 스토어 타입 정의
interface DataStore {
data: Data | null;
setData: (data: Data) => void;
}

const useDataStore = create<DataStore>((set) => ({
data: null,
setData: (data: Data) => set({ data }),
}));

export default useDataStore;
Loading