mirror of
https://github.com/sunrin-ana/2025-SSF-Frontend.git
synced 2026-03-09 18:30:00 +00:00
aa
This commit is contained in:
parent
afe581ec34
commit
ba3b85d622
12 changed files with 683 additions and 310 deletions
|
|
@ -5,7 +5,7 @@ import { getCookie } from "~/utils/cookie";
|
|||
export const BuyModal = component$(({ showBuyModal, item, mydotory, itemdotory}: {showBuyModal: Signal<boolean>, item: any, mydotory: number, itemdotory: number}) => {
|
||||
const handleBuy = $(async() => {
|
||||
try {
|
||||
const res = await axios.post(`http://localhost:8000/api/store/${item.id}?product_name=${item.name}`, {
|
||||
const res = await axios.post(`http://localhost:8000/api/store/0?product_name=${item.name}`, {
|
||||
}, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${getCookie("access_token")}`,
|
||||
|
|
|
|||
0
src/components/room/DragRommGrid.tsx
Normal file
0
src/components/room/DragRommGrid.tsx
Normal file
|
|
@ -16,7 +16,7 @@ export default component$(({ furniture, avatar, roomType }: { furniture: Signal<
|
|||
top_clothe_type: "",
|
||||
bottom_clothe_type: ""
|
||||
});
|
||||
|
||||
const furnitureItems = useSignal<FurnitureItem[]>([]);
|
||||
useVisibleTask$(({ track }) => {
|
||||
track(() => avatar.value);
|
||||
console.log(avatar.value);
|
||||
|
|
@ -26,42 +26,43 @@ export default component$(({ furniture, avatar, roomType }: { furniture: Signal<
|
|||
top_clothe_type: typechecker(avatar.value.top_clothe_type),
|
||||
bottom_clothe_type: typechecker(avatar.value.bottom_clothe_type),
|
||||
};
|
||||
furnitureItems.value = [furniture.value];
|
||||
console.log(checkedAvatar.value);
|
||||
})
|
||||
const furnitureItems = useSignal<FurnitureItem[]>([
|
||||
{
|
||||
name: '큰 식물1',
|
||||
image_path: 'public/funiture/큰 식물.png',
|
||||
x: 1,
|
||||
y: 1
|
||||
},
|
||||
{
|
||||
name: '녹색 침대1',
|
||||
image_path: 'public/funiture/녹색 침대-90.png',
|
||||
x: 3,
|
||||
y: 3
|
||||
},
|
||||
{
|
||||
name: '쓰레기통열림1',
|
||||
image_path: 'public/funiture/쓰레기통열림.png',
|
||||
x: 5,
|
||||
y: 5
|
||||
},
|
||||
{
|
||||
name: '어항1',
|
||||
image_path: 'public/funiture/어항-0.png',
|
||||
x: 7,
|
||||
y: 7
|
||||
}
|
||||
]);
|
||||
// const furnitureItems = useSignal<FurnitureItem[]>([
|
||||
// {
|
||||
// name: '큰 식물1',
|
||||
// image_path: 'public/funiture/큰 식물.png',
|
||||
// x: 1,
|
||||
// y: 1
|
||||
// },
|
||||
// {
|
||||
// name: '녹색 침대1',
|
||||
// image_path: 'public/funiture/녹색 침대-90.png',
|
||||
// x: 3,
|
||||
// y: 3
|
||||
// },
|
||||
// {
|
||||
// name: '쓰레기통열림1',
|
||||
// image_path: 'public/funiture/쓰레기통열림.png',
|
||||
// x: 5,
|
||||
// y: 5
|
||||
// },
|
||||
// {
|
||||
// name: '어항2',
|
||||
// image_path: 'public/funiture/어항-0.png',
|
||||
// x: 7,
|
||||
// y: 7
|
||||
// }
|
||||
// ]);
|
||||
|
||||
// 현재 드래그 중인 가구
|
||||
const draggedItem = useSignal<FurnitureItem | null>(null);
|
||||
// 드래그 시작 시 호출
|
||||
const handleDragStart = $((item: FurnitureItem, e: Event) => {
|
||||
e.preventDefault();
|
||||
draggedItem.value = item;
|
||||
});
|
||||
// const draggedItem = useSignal<FurnitureItem | null>(null);
|
||||
// // 드래그 시작 시 호출
|
||||
// const handleDragStart = $((item: FurnitureItem, e: Event) => {
|
||||
// e.preventDefault();
|
||||
// draggedItem.value = item;
|
||||
// });
|
||||
|
||||
// 드래그 오버 시 기본 동작 방지
|
||||
const handleDragOver = $((e: Event) => {
|
||||
|
|
@ -72,29 +73,35 @@ export default component$(({ furniture, avatar, roomType }: { furniture: Signal<
|
|||
const handleCellClick = $((x: number, y: number, e: Event) => {
|
||||
e.preventDefault();
|
||||
console.log(`Cell clicked: (${x}, ${y})`);
|
||||
furnitureItems.value = furnitureItems.value.map(item =>
|
||||
item.name === furniture.value?.name
|
||||
? { ...item, x: x, y: y }
|
||||
: item
|
||||
);
|
||||
// draggedItem.value = null;
|
||||
});
|
||||
|
||||
// 드롭 시 호출
|
||||
const handleDrop = $((cellX: number, cellY: number, e: Event) => {
|
||||
e.preventDefault();
|
||||
if (!draggedItem.value) return;
|
||||
// const handleDrop = $((cellX: number, cellY: number, e: Event) => {
|
||||
// e.preventDefault();
|
||||
// if (!draggedItem.value) return;
|
||||
|
||||
// 이미 해당 위치에 다른 가구가 있는지 확인
|
||||
const isOccupied = furnitureItems.value.some(
|
||||
item => item.x === cellX && item.y === cellY
|
||||
);
|
||||
// // 이미 해당 위치에 다른 가구가 있는지 확인
|
||||
// const isOccupied = furnitureItems.value.some(
|
||||
// item => item.x === cellX && item.y === cellY
|
||||
// );
|
||||
|
||||
if (!isOccupied) {
|
||||
// 가구 위치 업데이트
|
||||
furnitureItems.value = furnitureItems.value.map(item =>
|
||||
item.name === draggedItem.value?.name
|
||||
? { ...item, x: cellX, y: cellY }
|
||||
: item
|
||||
);
|
||||
}
|
||||
// if (!isOccupied) {
|
||||
// // 가구 위치 업데이트
|
||||
// furnitureItems.value = furnitureItems.value.map(item =>
|
||||
// item.name === draggedItem.value?.name
|
||||
// ? { ...item, x: cellX, y: cellY }
|
||||
// : item
|
||||
// );
|
||||
// }
|
||||
|
||||
draggedItem.value = null;
|
||||
});
|
||||
// draggedItem.value = null;
|
||||
// });
|
||||
|
||||
|
||||
// 10x10 그리드 셀 생성
|
||||
|
|
@ -125,40 +132,21 @@ export default component$(({ furniture, avatar, roomType }: { furniture: Signal<
|
|||
/>
|
||||
|
||||
{/* Grid overlay */}
|
||||
<div class="grid-overlay">
|
||||
<div class="grid-overlay ">
|
||||
{gridCells.map((cell) => (
|
||||
<div
|
||||
key={`${cell.x}-${cell.y}`}
|
||||
class="grid-cell"
|
||||
style={{
|
||||
gridColumn: cell.x,
|
||||
gridRow: cell.y,
|
||||
position: 'relative',
|
||||
width: '64px',
|
||||
height: '64px',
|
||||
// border: '1px dashed rgba(255, 255, 255, 0.1)',
|
||||
cursor: 'pointer',
|
||||
backgroundColor: cell.furniture ? 'rgba(0, 0, 0, 0.2)' : 'transparent'
|
||||
}}
|
||||
onDragOver$={handleDragOver}
|
||||
onDrop$={ e => handleDrop(cell.x, cell.y, e)}
|
||||
// onDragOver$={handleDragOver}
|
||||
// onDrop$={ e => handleDrop(cell.x, cell.y, e)}
|
||||
onClick$={ e => handleCellClick(cell.x, cell.y, e)}
|
||||
>
|
||||
{cell.furniture && (
|
||||
<img
|
||||
src={`http://localhost:8000/${cell.furniture.src}`}
|
||||
alt={cell.furniture.name}
|
||||
draggable
|
||||
onDragStart$={ e => handleDragStart(furnitureItems.value.find(f => f.name === cell.furniture?.name)!, e)}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
objectFit: 'contain',
|
||||
imageRendering: 'pixelated',
|
||||
cursor: 'move',
|
||||
zIndex: 10
|
||||
}}
|
||||
// draggable
|
||||
// onDragStart$={ e => handleDragStart(furnitureItems.value.find(f => f.name === cell.furniture?.name)!, e)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -198,17 +186,6 @@ const STYLES = `
|
|||
object-fit: cover;
|
||||
}
|
||||
|
||||
.grid-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(10, 1fr);
|
||||
grid-template-rows: repeat(10, 1fr);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.avatar-wrapper {
|
||||
position: absolute;
|
||||
|
|
@ -257,7 +234,7 @@ const STYLES = `
|
|||
grid-template-columns: repeat(10, 1fr);
|
||||
grid-template-rows: repeat(10, 1fr);
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
|
||||
}
|
||||
|
||||
.grid-overlay div {
|
||||
|
|
@ -287,7 +264,18 @@ const STYLES = `
|
|||
transform: translate(-50%, -50%);
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.grid-overlay div#oneone>img {
|
||||
width: 70px;
|
||||
image-rendering: pixelated;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
.grid-overlay div#twoone>img {
|
||||
width: 140px;
|
||||
image-rendering: pixelated;
|
||||
position: absolute;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.avatar-wrapper img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
|
|
|||
140
src/components/room/ShowRoomGrid.tsx
Normal file
140
src/components/room/ShowRoomGrid.tsx
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
import { component$, useStylesScoped$ , useVisibleTask$ } from "@builder.io/qwik";
|
||||
|
||||
interface FurnitureItem {
|
||||
image_path: string;
|
||||
x: number;
|
||||
y: number;
|
||||
size?: "one" | "two"; // 크기 구분 (one = 70px, two = 140px)
|
||||
}
|
||||
|
||||
interface AvatarItem {
|
||||
avatar_type: {name: string, path: string};
|
||||
top_clothe_type: {name: string, path: string};
|
||||
bottom_clothe_type: {name: string, path: string};
|
||||
}
|
||||
|
||||
interface ShowRoomGridProps {
|
||||
roomSrc: string; // 방 배경
|
||||
furnitures: FurnitureItem[]; // 가구 리스트
|
||||
avatars: AvatarItem; // 아바타 이미지 리스트
|
||||
}
|
||||
|
||||
export default component$((props: ShowRoomGridProps) => {
|
||||
console.log(props.roomSrc);
|
||||
console.log(props.furnitures + " furnitures");
|
||||
console.log(props.avatars + " avatars");
|
||||
useStylesScoped$(STYLES);
|
||||
useVisibleTask$(() => {
|
||||
});
|
||||
return (
|
||||
<div class="room-wrapper">
|
||||
{/* 배경 */}
|
||||
<img src={"http://localhost:8000/public/room/"+props.roomSrc+".png"} class="room" />
|
||||
|
||||
{/* 10x10 격자 */}
|
||||
<div class="grid-overlay">
|
||||
{Array.from({ length: 100 }).map((_, idx) => {
|
||||
const item = props.furnitures.find((f) => f.x*10 + f.y === idx);
|
||||
console.log(item);
|
||||
return (
|
||||
<div
|
||||
key={idx}
|
||||
class={
|
||||
item?.size === "one"
|
||||
? "oneone"
|
||||
: item?.size === "two"
|
||||
? "twoone"
|
||||
: undefined
|
||||
}
|
||||
style={
|
||||
item?.size === "two"
|
||||
? { gridColumn: `span 2`, gridRow: `span 1` }
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{item && <img src={"http://localhost:8000/" + item.image_path} />}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* 아바타 */}
|
||||
<div class="avatar-wrapper">
|
||||
|
||||
<img src={"http://localhost:8000/"+props.avatars.avatar_type.path} />
|
||||
<img src={"http://localhost:8000/"+props.avatars.top_clothe_type.path} />
|
||||
<img src={"http://localhost:8000/"+props.avatars.bottom_clothe_type.path} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const STYLES = `
|
||||
.room-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 700px;
|
||||
height: 700px;
|
||||
position: relative;
|
||||
}
|
||||
.room {
|
||||
position: absolute;
|
||||
z-index: 1 !important;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.grid-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 700px;
|
||||
height: 700px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(10, 1fr);
|
||||
grid-template-rows: repeat(10, 1fr);
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
.grid-overlay div {
|
||||
/* border: 1px solid rgba(0,0,0,0.2); */
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
// .grid-overlay div.oneone > img {
|
||||
// width: 140px;
|
||||
// image-rendering: pixelated;
|
||||
// position: absolute;
|
||||
// bottom: 0;
|
||||
// }
|
||||
// .grid-overlay div.twoone > img {
|
||||
// width: 140px;
|
||||
// image-rendering: pixelated;
|
||||
// position: absolute;
|
||||
// transform: translate(-50%, -50%);
|
||||
// }
|
||||
.avatar-wrapper {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
position: absolute;
|
||||
top: 70%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 99;
|
||||
}
|
||||
.avatar-wrapper img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
image-rendering: pixelated;
|
||||
z-index: 99;
|
||||
}
|
||||
`;
|
||||
|
|
@ -5,7 +5,7 @@ import { DocumentHead } from "@builder.io/qwik-city";
|
|||
import { useLocation } from "@builder.io/qwik-city";
|
||||
import axios from "axios";
|
||||
import { routeLoader$ } from "@builder.io/qwik-city";
|
||||
export const onRequest: RequestHandler = async ({ cookie, params, sharedMap}) => {
|
||||
export const onGet: RequestHandler = async ({ cookie, params, sharedMap}) => {
|
||||
|
||||
console.log(params.username + "의 상점 페이지로 들어옴");
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ export const onRequest: RequestHandler = async ({ cookie, params, sharedMap}) =>
|
|||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
},
|
||||
});
|
||||
sharedMap.set("dotory", res.data ?? 0);
|
||||
sharedMap.set("dotory", res.data.dotory ?? 0);
|
||||
console.log(res.data ?? "no data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
|
@ -29,8 +29,8 @@ export default component$(() => {
|
|||
const location = useLocation();
|
||||
const dotory = useDotory();
|
||||
|
||||
console.log(location.url.pathname);
|
||||
console.log("/"+location.params.username+"/store");
|
||||
// console.log(location.url.pathname);
|
||||
// console.log(location.params.username+"/store");
|
||||
return (
|
||||
<div class="w-full h-full flex flex-col">
|
||||
<div class="flex justify-center flex-col gap-4 p-2 items-center w-full">
|
||||
|
|
@ -40,8 +40,6 @@ export default component$(() => {
|
|||
<Link href={`/${location.params.username}/room`} class={`${location.url.pathname === `/${location.params.username}/room` ? "bg-[#FAD659]" : "bg-white"} text-gray-800 px-4 py-2 rounded-lg font-medium`}>방</Link>
|
||||
</div>
|
||||
<div class="flex md:flex-row flex-col">
|
||||
{/* <div class="w-12 h-12 bg-[#33231A] [clip-path:polygon(20%_0,100%_0,80%_100%,20%_100%,0_80%,0_20%)]">
|
||||
</div> */}
|
||||
<div class="ml-auto bg-[#CC8A6A] text-default px-4 py-2 rounded-lg font-medium">도토리: {dotory.value}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -45,39 +45,18 @@ interface Room {
|
|||
room_image_path: string;
|
||||
}
|
||||
export const useRoomLoader = routeLoader$(async ({cookie}) => {
|
||||
const headers = {
|
||||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
}
|
||||
try {
|
||||
const myRoom = await axios.get("http://localhost:8000/api/room/layout", {
|
||||
headers: {
|
||||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
},
|
||||
})
|
||||
const myAvatar = await axios.get("http://localhost:8000/api/avatar", {
|
||||
headers: {
|
||||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
},
|
||||
})
|
||||
const roomType = await axios.get("http://localhost:8000/api/room/types", {
|
||||
headers: {
|
||||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
},
|
||||
})
|
||||
const furniture = await axios.get("http://localhost:8000/api/room/my", {
|
||||
headers: {
|
||||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
},
|
||||
})
|
||||
const avatarType = await axios.get("http://localhost:8000/api/avatar/options", {
|
||||
headers: {
|
||||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
},
|
||||
})
|
||||
const roomTypeData = roomType.data;
|
||||
const avatar : Avatar = myAvatar.data;
|
||||
const room : Room = myRoom.data;
|
||||
const furnitureData = furniture.data;
|
||||
const avatarTypeData = avatarType.data;
|
||||
console.log(myRoom.data);
|
||||
return {myData : {room: room, avatar: avatar}, selectionData: {roomType: roomTypeData, furniture: furnitureData, avatarType: avatarTypeData}};
|
||||
const [myRoom, myAvatar, roomType, furniture, avatarType] = await Promise.all([
|
||||
axios.get("http://localhost:8000/api/room/layout", { headers }),
|
||||
axios.get("http://localhost:8000/api/avatar", { headers }),
|
||||
axios.get("http://localhost:8000/api/room/types", { headers }),
|
||||
axios.get("http://localhost:8000/api/room/my", { headers }),
|
||||
axios.get("http://localhost:8000/api/avatar/options", { headers }),
|
||||
]);
|
||||
return {myData : {room: myRoom.data, avatar: myAvatar.data}, selectionData: {roomType: roomType.data, furniture: furniture.data, avatarType: avatarType.data}};
|
||||
} catch (error : any) {
|
||||
console.error(error);
|
||||
return error.response?.data?.detail || 'Room not found';
|
||||
|
|
@ -85,8 +64,10 @@ export const useRoomLoader = routeLoader$(async ({cookie}) => {
|
|||
})
|
||||
export default component$(() => {
|
||||
const data = useRoomLoader();
|
||||
const selectedFurniture = useSignal<Furniture[]>([]); // 유저 선택 가구
|
||||
const selectedType = useSignal("furniture"); // 헤더에서 가구, 아바타, 배경 구분
|
||||
const selectedFurnitures = useSignal<Array<Furniture & {x?: number, y?: number}>>([]);
|
||||
|
||||
const selectedType = useSignal<"furniture" | "avatar" | "background">("furniture");
|
||||
const editingPosition = useSignal<number | null>(null);
|
||||
const selectedRoomType = useSignal("room_1");
|
||||
const selectedAvatar = useSignal<SetAvatarType>({
|
||||
avatar_type: "",
|
||||
|
|
@ -100,99 +81,31 @@ export default component$(() => {
|
|||
selectedAvatar.value.bottom_clothe_type = data.value.myData.avatar.bottom_clothe_type.name;
|
||||
|
||||
})
|
||||
const deleteFurniture = $((selectedFurniture : Furniture) => {
|
||||
const furnitureRes = axios.delete("http://localhost:8000/api/room/furniture", {
|
||||
data: {
|
||||
furniture_name: selectedFurniture.furniture_name,
|
||||
x: selectedFurniture.x,
|
||||
y: selectedFurniture.y,
|
||||
},
|
||||
headers: {
|
||||
Authorization: `Bearer ${getCookie("access_token")}`,
|
||||
},
|
||||
})
|
||||
})
|
||||
// const getNewState = async () => {
|
||||
// const myRoom = await axios.get("http://localhost:8000/api/room/layout", {
|
||||
// headers: {
|
||||
// Authorization: `Bearer ${getCookie("access_token")}`,
|
||||
// },
|
||||
// })
|
||||
// const myAvatar = await axios.get("http://localhost:8000/api/avatar", {
|
||||
// headers: {
|
||||
// Authorization: `Bearer ${getCookie("access_token")}`,
|
||||
// },
|
||||
// })
|
||||
// const roomType = await axios.get("http://localhost:8000/api/room/types", {
|
||||
// headers: {
|
||||
// Authorization: `Bearer ${getCookie("access_token")}`,
|
||||
// },
|
||||
// })
|
||||
// const furniture = await axios.get("http://localhost:8000/api/room/my", {
|
||||
// headers: {
|
||||
// Authorization: `Bearer ${getCookie("access_token")}`,
|
||||
// },
|
||||
// })
|
||||
// const avatarType = await axios.get("http://localhost:8000/api/avatar/options", {
|
||||
// headers: {
|
||||
// Authorization: `Bearer ${getCookie("access_token")}`,
|
||||
// },
|
||||
// })
|
||||
// const roomTypeData = roomType.data;
|
||||
// const avatar : Avatar = myAvatar.data.avatar;
|
||||
// const room : Room = myRoom.data;
|
||||
// const furnitureData = furniture.data;
|
||||
// const avatarTypeData = avatarType.data;
|
||||
// console.log(myRoom.data);
|
||||
// }
|
||||
const handleChange = $( async () => {
|
||||
console.log("handleChange");
|
||||
const deleteFurniture = $(async (selectedFurniture : Furniture) => {
|
||||
try {
|
||||
// 배경 설정
|
||||
console.log(selectedRoomType.value);
|
||||
const roomRes = await axios.patch("http://localhost:8000/api/room/",
|
||||
{
|
||||
type: selectedRoomType.value
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${getCookie("access_token")}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
const avatarRes = await axios.put("http://localhost:8000/api/avatar", {
|
||||
|
||||
avatar_type: selectedAvatar.value.avatar_type,
|
||||
top_clothe_type: selectedAvatar.value.top_clothe_type,
|
||||
bottom_clothe_type: selectedAvatar.value.bottom_clothe_type,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${getCookie("access_token")}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
// for (let i = 0; i < selectedFurniture.value.length; i++) {
|
||||
// const furnitureRes = await axios.post("http://localhost:8000/api/room/furniture", {
|
||||
// furniture_name: selectedFurniture.value[i].furniture_name,
|
||||
// x: selectedFurniture.value[i].x,
|
||||
// y: selectedFurniture.value[i].y,
|
||||
// },
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: `Bearer ${getCookie("access_token")}`,
|
||||
// },
|
||||
// })
|
||||
// }
|
||||
// getNewState();
|
||||
console.log(roomRes.data);
|
||||
console.log(avatarRes.data);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
await axios.delete(`http://localhost:8000/api/room/furniture?x=${selectedFurniture.x}&y=${selectedFurniture.y}&furniture_name=${selectedFurniture.furniture_name}`, {headers: {Authorization: `Bearer ${getCookie("access_token")}`}});
|
||||
selectedFurnitures.value = selectedFurnitures.value.filter((f : Furniture) => f.furniture_name !== selectedFurniture.furniture_name);
|
||||
} catch (error : any) {console.error(error);}
|
||||
})
|
||||
const handleCancel = $(() => {
|
||||
console.log("handleCancel");
|
||||
const addFurniture = $(async (selectedFurniture : Furniture) => {
|
||||
try { await axios.post("http://localhost:8000/api/room/furniture", {furniture_name: selectedFurniture.furniture_name,x: selectedFurniture.x,y: selectedFurniture.y,}, { headers: { Authorization: `Bearer ${getCookie("access_token")}`,},},)
|
||||
} catch (error : any) {console.error(error);}
|
||||
})
|
||||
useTask$(({track}) => {
|
||||
track(() => selectedFurnitures.value);
|
||||
try {
|
||||
for (let i = 0; i < selectedFurnitures.value.length; i++) {
|
||||
if(data.value.myData.room.room.furniture.some((f : Furniture) => f.furniture_name === selectedFurnitures.value[i].furniture_name)) {deleteFurniture(selectedFurnitures.value[i]);}
|
||||
else { addFurniture(selectedFurnitures.value[i]);}
|
||||
}
|
||||
} catch (error : any) {console.error(error);}
|
||||
})
|
||||
|
||||
const handleChange = $( async () => {
|
||||
try {
|
||||
await axios.patch("http://localhost:8000/api/room/", {type: selectedRoomType.value}, {headers: {Authorization: `Bearer ${getCookie("access_token")}`}});
|
||||
await axios.put("http://localhost:8000/api/avatar", {avatar_type: selectedAvatar.value.avatar_type,top_clothe_type: selectedAvatar.value.top_clothe_type,bottom_clothe_type: selectedAvatar.value.bottom_clothe_type,}, {headers: {Authorization: `Bearer ${getCookie("access_token")}`}});
|
||||
} catch (error) {console.log(error);}
|
||||
})
|
||||
return (
|
||||
<div class="flex flex-col h-full p-4">
|
||||
|
|
@ -201,7 +114,7 @@ export default component$(() => {
|
|||
{/* Room Preview */}
|
||||
<div class="flex-1 bg-white rounded-xl border border-gray-200 p-4">
|
||||
<div class="h-full flex items-center justify-center">
|
||||
<RoomGrid furniture={selectedFurniture} avatar={selectedAvatar} roomType={selectedRoomType} />
|
||||
<RoomGrid furniture={selectedFurnitures} avatar={selectedAvatar} roomType={selectedRoomType} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -251,12 +164,81 @@ export default component$(() => {
|
|||
<div class="flex-1 overflow-y-auto p-4">
|
||||
<div class="flex flex-col gap-3">
|
||||
{selectedType.value === "furniture" ? (
|
||||
data.value.selectionData.furniture.map((furniture: Furniture) => (
|
||||
<div key={furniture.furniture_name} class={`flex items-center flex-col gap-2 rounded-t-lg` } onClick$={() => {if(selectedFurniture.value.includes(furniture)) selectedFurniture.value = selectedFurniture.value.filter((item: Furniture) => item !== furniture); else selectedFurniture.value.push(furniture);}}>
|
||||
<img src={`http://localhost:8000/${furniture.image_path}`} alt={furniture.furniture_name} style={{imageRendering: "pixelated"}} class={` object-contain w-24 h-24 ${selectedFurniture.value.includes(furniture) ? "border-[2px] border-[#FAD659]" : ""}`} />
|
||||
<span class="text-center font-bold rounded-b-lg w-24 h-12 bg-[#E5E2B6]">{furniture.furniture_name}</span>
|
||||
data.value.selectionData.furniture.map((furniture: Furniture) => {
|
||||
const isSelected = selectedFurnitures.value.some(f => f.furniture_name === furniture.furniture_name);
|
||||
const selectedItem = selectedFurnitures.value.find(f => f.furniture_name === furniture.furniture_name);
|
||||
|
||||
return (
|
||||
<div key={furniture.furniture_name} class="flex flex-col items-center gap-2">
|
||||
<div
|
||||
class={`flex flex-col items-center gap-2 rounded-t-lg ${isSelected ? 'ring-2 ring-yellow-400' : ''}`}
|
||||
onClick$={() => {
|
||||
if (isSelected) {
|
||||
selectedFurnitures.value = selectedFurnitures.value.filter(
|
||||
item => item.furniture_name !== furniture.furniture_name
|
||||
);
|
||||
} else {
|
||||
selectedFurnitures.value = [...selectedFurnitures.value, {
|
||||
...furniture,
|
||||
x: 0,
|
||||
y: 0
|
||||
}];
|
||||
}
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={`http://localhost:8000/${furniture.image_path}`}
|
||||
alt={furniture.furniture_name}
|
||||
style={{imageRendering: "pixelated"}}
|
||||
class="object-contain w-24 h-24"
|
||||
/>
|
||||
<span class="text-center font-bold rounded-b-lg w-24 h-12 bg-[#E5E2B6] flex items-center justify-center">
|
||||
{furniture.furniture_name}
|
||||
</span>
|
||||
</div>
|
||||
)))
|
||||
|
||||
{isSelected && (
|
||||
<div class="flex gap-2 mt-1">
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
max="10"
|
||||
value={selectedItem?.x || ''}
|
||||
onInput$={(e) => {
|
||||
const value = (e.target as HTMLInputElement).value;
|
||||
const index = selectedFurnitures.value.findIndex(f => f.furniture_name === furniture.furniture_name);
|
||||
if (index !== -1) {
|
||||
const updated = [...selectedFurnitures.value];
|
||||
updated[index] = { ...updated[index], x: parseInt(value) || 0 };
|
||||
selectedFurnitures.value = updated;
|
||||
}
|
||||
}}
|
||||
class="w-12 px-1 text-center border rounded"
|
||||
placeholder="X"
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
max="10"
|
||||
value={selectedItem?.y || ''}
|
||||
onInput$={(e) => {
|
||||
const value = (e.target as HTMLInputElement).value;
|
||||
const index = selectedFurnitures.value.findIndex(f => f.furniture_name === furniture.furniture_name);
|
||||
if (index !== -1) {
|
||||
const updated = [...selectedFurnitures.value];
|
||||
updated[index] = { ...updated[index], y: parseInt(value) || 0 };
|
||||
selectedFurnitures.value = updated;
|
||||
}
|
||||
}}
|
||||
class="w-12 px-1 text-center border rounded"
|
||||
placeholder="Y"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
))
|
||||
:
|
||||
selectedType.value === "avatar" ? (
|
||||
<div class="flex flex-col gap-3 ">
|
||||
|
|
|
|||
|
|
@ -34,6 +34,16 @@ interface ShopResponse {
|
|||
|
||||
export const useShopLoader = routeLoader$(async ({cookie}) => {
|
||||
try {
|
||||
// const getDotory = await axios.put(`http://localhost:8000/api/store?dotory_num=100`, {
|
||||
// headers: {
|
||||
// Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
// },
|
||||
// // });
|
||||
// const dotory = await axios.get(`http://localhost:8000/api/store`, {
|
||||
// headers: {
|
||||
// Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
// },
|
||||
// });
|
||||
const res = await axios.get(`http://localhost:8000/api/room/catalog`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
|
|
@ -51,14 +61,15 @@ export const useShopLoader = routeLoader$(async ({cookie}) => {
|
|||
// });
|
||||
console.log(res.data);
|
||||
console.log(avatar.data);
|
||||
return {storeData: res.data, avatarData: avatar.data, dotory: 0};
|
||||
|
||||
return {storeData: res.data, avatarData: avatar.data, dotory: 80};
|
||||
} catch (error : any) {
|
||||
console.error(error);
|
||||
return { storeData: [], avatarData: null, dotory: 0};
|
||||
}
|
||||
});
|
||||
export default component$(() => {
|
||||
const data = useShopLoader() as { value: ShopResponse };
|
||||
const data = useShopLoader();
|
||||
const selectedItem = useSignal<ShopItem | null>(null);
|
||||
const showBuyModal = useSignal(false);
|
||||
return (
|
||||
|
|
@ -84,7 +95,7 @@ export default component$(() => {
|
|||
class="bg-diary-color hover:bg-diary-icon-hover md:w-full text-black px-4 py-2 rounded-3xl font-bold transition-all duration-200 flex items-center gap-2 z-10 relative"
|
||||
onClick$={() => {showBuyModal.value = true}}>
|
||||
구매하기
|
||||
<i class="bi bi-cart-fill text-3xl text-black"></i>
|
||||
<i class="bi bi-cart text-3xl text-black"></i>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,44 +1,272 @@
|
|||
import { component$, useSignal } from "@builder.io/qwik";
|
||||
import { DocumentHead , RequestHandler, routeLoader$} from "@builder.io/qwik-city";
|
||||
import { useNavigate } from "@builder.io/qwik-city";
|
||||
import { $, component$, useSignal, useVisibleTask$, NoSerialize, useTask$ } from "@builder.io/qwik";
|
||||
import { routeLoader$, useLocation, useNavigate } from "@builder.io/qwik-city";
|
||||
import axios from "axios";
|
||||
const diaryLoader = routeLoader$<{ message: string }>(async ({params, cookie, redirect}) => {
|
||||
|
||||
try {
|
||||
console.log(params.username + "의 방명록 가져오기");
|
||||
const myInfo = await axios.get(`http://localhost:8000/api/user/me`, {
|
||||
import { noSerialize } from "@builder.io/qwik";
|
||||
// import { PhotoUploadModal } from "~/components/features/diary/UploadImages";
|
||||
import { getCookie } from "~/utils/cookie";
|
||||
interface FileInfo {
|
||||
name: string;
|
||||
size: number;
|
||||
type: string;
|
||||
lastModified: number;
|
||||
url: string;
|
||||
}
|
||||
interface DiaryData {
|
||||
content: string;
|
||||
title: string;
|
||||
category: string;
|
||||
images: File[];
|
||||
}
|
||||
export const diaryDataLoader = routeLoader$(async ({params, cookie}) => {
|
||||
const access_token = cookie.get("access_token");
|
||||
const diary_id = params.diary_id;
|
||||
const diaryData = await axios.get(`http://localhost:8000/api/diary/${diary_id}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
Authorization: `Bearer ${access_token?.value}`,
|
||||
},
|
||||
});
|
||||
if(myInfo.data.username !== params.username) {
|
||||
return redirect(302, `/diary/${params.diary_id}`);
|
||||
}
|
||||
const res = await axios.get(`http://localhost:8000/api/diary/${params.diary_id}`);
|
||||
console.log(res.data);
|
||||
return res.data;
|
||||
} catch (error : any) {
|
||||
console.error(error);
|
||||
return error.response?.data?.detail || 'Diary not found';
|
||||
return diaryData.data;
|
||||
})
|
||||
export default component$(() => {
|
||||
const diaryData = diaryDataLoader();
|
||||
const content = useSignal('');
|
||||
const title = useSignal('');
|
||||
const category = useSignal('');
|
||||
const selectedImages = useSignal<File[]>([] );
|
||||
const textareaRef = useSignal<HTMLTextAreaElement>();
|
||||
const nav = useNavigate();
|
||||
const location = useLocation();
|
||||
const showPhotoUploadModal = useSignal(false);
|
||||
const fileInfo = useSignal<FileInfo | null>(null);
|
||||
const fileRef = useSignal<NoSerialize<File> | null>(null);
|
||||
const error = useSignal('');
|
||||
// const fileInputRef = useSignal<HTMLInputElement>();
|
||||
useTask$(() => {
|
||||
content.value = diaryData.value.content;
|
||||
title.value = diaryData.value.title;
|
||||
category.value = diaryData.value.category;
|
||||
selectedImages.value = diaryData.value.images;
|
||||
})
|
||||
const handleFileSelect = $(async (selectedFile: File) => {
|
||||
if (selectedFile && selectedFile.type.startsWith('image/')) {
|
||||
fileInfo.value = {
|
||||
name: selectedFile.name,
|
||||
size: selectedFile.size,
|
||||
type: selectedFile.type,
|
||||
lastModified: selectedFile.lastModified,
|
||||
url: URL.createObjectURL(selectedFile)
|
||||
};
|
||||
fileRef.value = noSerialize(selectedFile);
|
||||
error.value = '';
|
||||
console.log(fileInfo.value);
|
||||
} else {
|
||||
error.value = '이미지 파일만 업로드 가능합니다.';
|
||||
fileInfo.value = null;
|
||||
fileRef.value = null;
|
||||
}
|
||||
});
|
||||
|
||||
const handleRemoveImage = $((index: number) => {
|
||||
selectedImages.value = selectedImages.value.filter((_, i) => i !== index);
|
||||
});
|
||||
|
||||
const handleSend = $(async () => {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('title', title.value);
|
||||
formData.append('content', content.value);
|
||||
formData.append('category', category.value);
|
||||
|
||||
// Append each image file
|
||||
selectedImages.value.forEach((file) => {
|
||||
formData.append('file', file);
|
||||
});
|
||||
|
||||
await axios.put(`http://localhost:8000/api/diary/${location.params.diary_id}`, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
Authorization: `Bearer ${getCookie("access_token")}`,
|
||||
},
|
||||
});
|
||||
|
||||
nav(`/${location.params.username}/diary`);
|
||||
} catch (error: any) {
|
||||
console.error('Error creating diary:', error);
|
||||
}
|
||||
});
|
||||
useVisibleTask$(({ track }) => {
|
||||
track(() => content.value);
|
||||
if (textareaRef.value) {
|
||||
textareaRef.value.style.height = 'auto';
|
||||
textareaRef.value.style.height = `${textareaRef.value.scrollHeight}px`;
|
||||
}
|
||||
});
|
||||
export default component$(() => {
|
||||
const navigate = useNavigate();
|
||||
const diaryData = diaryLoader();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>일기 수정</h1>
|
||||
<div class="p-6">
|
||||
<div class="flex justify-between items-center mb-8">
|
||||
<h1 class="text-2xl font-bold">일기 쓰기</h1>
|
||||
</div>
|
||||
<div class="border-b-2 border-text-default flex flex-row justify-between items-center">
|
||||
<input
|
||||
bind:value={title}
|
||||
type="text"
|
||||
placeholder="제목을 입력해주세요."
|
||||
class="w-full text-2xl font-bold p-2 focus:outline-none"
|
||||
/>
|
||||
<div class="flex gap-3">
|
||||
<button onClick$={() => nav(`/${location.params.username}/diary`)}>
|
||||
<i class="bi bi-trash-fill text-3xl text-black"></i>
|
||||
</button>
|
||||
<button onClick$={() => handleSend()}>
|
||||
<i class="bi bi-send-fill text-3xl text-black"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Image upload and preview section */}
|
||||
<div class="p-4">
|
||||
<div class="flex gap-2 overflow-x-auto py-2">
|
||||
{selectedImages.value.map((image, index) => (
|
||||
<div key={index} class="relative">
|
||||
<img
|
||||
src={URL.createObjectURL(image)}
|
||||
alt={`Preview ${index}`}
|
||||
class="h-24 w-24 object-cover rounded"
|
||||
/>
|
||||
<button
|
||||
onClick$={() => handleRemoveImage(index)}
|
||||
class="absolute -top-2 -right-2 bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
<button
|
||||
onClick$={() => showPhotoUploadModal.value = true}
|
||||
>
|
||||
<i class="bi bi-image-fill text-black text-2xl"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="relative">
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
bind:value={content}
|
||||
placeholder="본문을 입력해주세요"
|
||||
class="w-full min-h-[70vh] p-4 bg-white border border-text-default rounded-lg focus:outline-none resize-none leading-relaxed whitespace-pre-wrap"
|
||||
style={{
|
||||
backgroundImage: 'linear-gradient(#f1f1f1 1px, transparent 1px)',
|
||||
backgroundSize: '100% 1.5rem',
|
||||
lineHeight: '1.5rem',
|
||||
backgroundAttachment: 'local',
|
||||
backgroundPositionY: '0.75rem',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div >
|
||||
{selectedImages.value.map((file, index) => (
|
||||
<div key={index}>
|
||||
<img src={URL.createObjectURL(file)} alt={`Preview ${index}`} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{showPhotoUploadModal.value &&
|
||||
<div class="fixed inset-0 bg-black bg-opacity-45 flex items-center justify-center z-50" onClick$={() => showPhotoUploadModal.value = false}>
|
||||
<div class="bg-white rounded-lg w-[400px] p-6 shadow-xl relative" onClick$={(e) => e.stopPropagation()}>
|
||||
<button
|
||||
class="absolute top-4 right-4 text-xl text-black"
|
||||
onClick$={() => showPhotoUploadModal.value = false}
|
||||
aria-label="닫기"
|
||||
>
|
||||
<i class="bi bi-x-lg"></i>
|
||||
</button>
|
||||
|
||||
<h2 class="text-3xl font-bold text-center text-black">사진 업로드</h2>
|
||||
<p class="text-xs p-2 text-gray-500 text-center border-b-2 border-black mb-6">
|
||||
소중한 순간들을 기록하고 공유하세요
|
||||
</p>
|
||||
|
||||
<div
|
||||
class={`border-2 border-dashed rounded-md h-32 flex flex-col items-center justify-center text-sm cursor-pointer transition-colors ${
|
||||
fileInfo.value
|
||||
? 'border-green-300 bg-green-50 text-green-700'
|
||||
: 'border-gray-300 bg-gray-100 text-gray-500 hover:border-blue-400'
|
||||
}`}
|
||||
onDragOver$={(e) => e.preventDefault()}
|
||||
onDrop$={async (e) => {
|
||||
e.preventDefault();
|
||||
const files = e.dataTransfer?.files;
|
||||
if (files && files.length > 0) {
|
||||
await handleFileSelect(files[0]);
|
||||
}
|
||||
}}
|
||||
onClick$={async () => {
|
||||
if (fileRef.value) {
|
||||
try {
|
||||
|
||||
console.log('업로드됨:', {
|
||||
file: fileRef.value,
|
||||
fileInfo: fileInfo.value
|
||||
});
|
||||
|
||||
// 업로드 후 초기화
|
||||
fileInfo.value = null;
|
||||
fileRef.value = null;
|
||||
showPhotoUploadModal.value = false;
|
||||
} catch (err) {
|
||||
console.error('업로드 실패:', err);
|
||||
error.value = '파일 업로드 중 오류가 발생했습니다.';
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{fileInfo.value ? (
|
||||
<div class="text-center p-4">
|
||||
<i class="bi bi-check-circle-fill text-2xl mb-1"></i>
|
||||
<p class="font-medium">{fileInfo.value.name}</p>
|
||||
<p class="text-xs">{(fileInfo.value.size / 1024).toFixed(1)} KB</p>
|
||||
</div>
|
||||
) : (
|
||||
<div class="text-center p-4">
|
||||
<i class="bi bi-image-fill text-2xl mb-1"></i>
|
||||
<p>클릭 또는 사진을 드래그하세요</p>
|
||||
<p class="text-xs mt-1">JPG, PNG, GIF</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{error.value && (
|
||||
<p class="text-red-500 text-sm mt-2">{error.value}</p>
|
||||
)}
|
||||
|
||||
<button
|
||||
class="mt-6 w-full bg-[#FFAD84] hover:bg-[#ff9e6b] text-[#4b3c28] font-semibold py-2 rounded-md flex justify-center items-center gap-1 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
disabled={!fileInfo.value}
|
||||
onClick$={async () => {
|
||||
if (fileRef.value) {
|
||||
try {
|
||||
console.log('Uploading:', {
|
||||
file: fileRef.value,
|
||||
fileInfo: fileInfo.value
|
||||
});
|
||||
|
||||
selectedImages.value = [...selectedImages.value, fileRef.value];
|
||||
fileInfo.value = null;
|
||||
fileRef.value = null;
|
||||
} catch (err) {
|
||||
console.error('업로드 실패:', err);
|
||||
error.value = '파일 업로드 중 오류가 발생했습니다.';
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
업로드 <i class="bi bi-cloud-upload"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export const head: DocumentHead = {
|
||||
title: "일기수정하기",
|
||||
meta: [
|
||||
{
|
||||
name: "description",
|
||||
content: "유저가 쓴 일기의 상세정보",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -74,7 +74,7 @@ export default component$(() => {
|
|||
</div>
|
||||
|
||||
<div class="mt-8 flex flex-col gap-4">
|
||||
<div class="flex gap-4 overflow-auto">
|
||||
<div class="flex gap-4 overflow-auto border-t-[1px] border-b-[1px] border-text-default p-2">
|
||||
{diaryLoader.value.diary.images.map((image, index) => (
|
||||
<img key={index} src={`http://localhost:8000/${image}`} alt={`일기 ${index + 1}`} class="max-w-full h-auto max-h-64" />
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { component$, useSignal, $, useTask$, useContext } from "@builder.io/qwik";
|
||||
import { component$, useSignal, $, useVisibleTask$, useContext } from "@builder.io/qwik";
|
||||
import type { DocumentHead } from "@builder.io/qwik-city";
|
||||
import { useNavigate, useLocation, Link, routeLoader$ } from "@builder.io/qwik-city";
|
||||
import axios from "axios";
|
||||
|
|
@ -7,7 +7,7 @@ export const useDiaryLoader = routeLoader$( async ({cookie, params}) => {
|
|||
try {
|
||||
const userid = await axios.get(`http://localhost:8000/api/user/profile/${params.username}`);
|
||||
console.log(userid.data.id + "<- 이건 아이디");
|
||||
const res = await axios.get(`http://localhost:8000/api/diary/w/{user_id}?target_user_id=${userid.data.id}&skip=0&limit=6`, {
|
||||
const res = await axios.get(`http://localhost:8000/api/diary/w/${userid.data.id}?skip=0&limit=6`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
},
|
||||
|
|
@ -25,7 +25,7 @@ export default component$(() => {
|
|||
const entryLoader = useDiaryLoader();
|
||||
const entries = useSignal<DiaryEntry[]>([]);
|
||||
const filteredEntries = useSignal<DiaryEntry[]>([]);
|
||||
useTask$(() => {
|
||||
useVisibleTask$(() => {
|
||||
console.log( entryLoader.value.user);
|
||||
entries.value = entryLoader.value.diaries as DiaryEntry[];
|
||||
filteredEntries.value = entries.value;
|
||||
|
|
@ -39,21 +39,21 @@ export default component$(() => {
|
|||
});
|
||||
const handleMonthSelect = $((month : number) => {
|
||||
selectedMonth.value = month;
|
||||
console.log(selectedMonth.value);
|
||||
filteredEntries.value = entries.value.filter((entry) => {
|
||||
const entryMonth = new Date(entry.created_at).getMonth() + 1;
|
||||
return entryMonth === selectedMonth.value;
|
||||
});
|
||||
console.log(filteredEntries.value);
|
||||
console.log("<->" + selectedMonth.value);
|
||||
showMonth.value = false;
|
||||
});
|
||||
|
||||
const handleSearch = $(() => {
|
||||
if(searchQuery.value === '') {
|
||||
filteredEntries.value = entries.value;
|
||||
filteredEntries.value = [...entries.value];
|
||||
}
|
||||
else {
|
||||
filteredEntries.value = entries.value.filter((entry) => entry.title.includes(searchQuery.value));
|
||||
filteredEntries.value = [...entries.value.filter((entry) => entry.title.includes(searchQuery.value))];
|
||||
}
|
||||
console.log(filteredEntries.value);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { component$, useSignal, $, useTask$} from "@builder.io/qwik";
|
||||
import { component$, useSignal, $, useVisibleTask$} from "@builder.io/qwik";
|
||||
import type { DocumentHead } from "@builder.io/qwik-city";
|
||||
import { routeLoader$, useLocation } from "@builder.io/qwik-city";
|
||||
import { getCookie } from "~/utils/cookie";
|
||||
|
|
@ -70,18 +70,25 @@ export default component$(() => {
|
|||
const selectedMessage = useSignal<GuestbookContent>({} as GuestbookContent);
|
||||
const updatedMessage = useSignal('');
|
||||
const refreshMessages = $(async () => {
|
||||
try {
|
||||
const res = await axios.get<GuestbookContent[]>(`http://localhost:8000/api/guestbook/${loaderData.value.targetUser.id}`);
|
||||
messages.value = res.data;
|
||||
console.log(messages.value + " loader");
|
||||
} catch (error) {
|
||||
|
||||
console.log("방명록 가져오기 실패" +loaderData.value.targetUser.id);
|
||||
}
|
||||
});
|
||||
useTask$(() => {
|
||||
useVisibleTask$(() => {
|
||||
console.log("useTask");
|
||||
refreshMessages();
|
||||
messages.value = loaderData.value.messages;
|
||||
|
||||
});
|
||||
const handleSubmit = $(() => {
|
||||
const handleSubmit = $(async () => {
|
||||
if (!newMessage.value.trim()) return;
|
||||
try {
|
||||
axios.post(`http://localhost:8000/api/guestbook/`, {
|
||||
console.log(newMessage.value);
|
||||
await axios.post(`http://localhost:8000/api/guestbook`, {
|
||||
content: newMessage.value,
|
||||
target_user_id: loaderData.value.targetUser.id,
|
||||
}, {
|
||||
|
|
@ -96,16 +103,20 @@ export default component$(() => {
|
|||
}
|
||||
newMessage.value = '';
|
||||
});
|
||||
const handleEdit = $(() => {
|
||||
const handleEdit = $(async () => {
|
||||
console.log("수정 요청 보내기");
|
||||
if (!updatedMessage.value.trim()) {
|
||||
console.log("수정 내용이 없습니다.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
axios.put(`http://localhost:8000/api/guestbook/${selectedMessage.value.id}`, {
|
||||
await axios.put(`http://localhost:8000/api/guestbook/${selectedMessage.value.id}`, {
|
||||
content: updatedMessage.value,
|
||||
}, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${getCookie("access_token")}`,
|
||||
},
|
||||
});
|
||||
|
||||
refreshMessages();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
|
@ -154,9 +165,11 @@ export default component$(() => {
|
|||
</div>
|
||||
}
|
||||
{showUpdateModal.value && msg.id === selectedMessage.value.id && (
|
||||
<div
|
||||
<form
|
||||
class="absolute z-50 bg-white right-0 top-0 p-2 rounded-xl focus:outline-none w-full min-w-[220px]"
|
||||
onClick$={(e) => e.stopPropagation()} /* 외부 클릭으로 닫히는 건 부모가 처리하게 둘 수 있음 */
|
||||
// onClick$={(e) => e.stopPropagation()} /* 외부 클릭으로 닫히는 건 부모가 처리하게 둘 수 있음 */
|
||||
preventdefault:submit
|
||||
onSubmit$={handleEdit}
|
||||
>
|
||||
<div class="flex mt-2 justify-between">
|
||||
<p>수정할 내용을 입력해주세요.</p>
|
||||
|
|
@ -164,7 +177,7 @@ export default component$(() => {
|
|||
<button class="btn-cancel text-button-color-1 border-black" onClick$={() => showUpdateModal.value = false}>
|
||||
<i class="bi bi-x"></i>
|
||||
</button>
|
||||
<button class="btn-save text-diary-color border-black" onClick$={handleEdit}>
|
||||
<button class="btn-save text-diary-color border-black">
|
||||
<i class="bi bi-check"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -174,7 +187,7 @@ export default component$(() => {
|
|||
onInput$={(ev: any) => (updatedMessage.value = ev.target.value)}
|
||||
class="w-full p-2 border border-input-border-color rounded-xl"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -191,7 +204,7 @@ export default component$(() => {
|
|||
{/* <button class="absolute right-12 w-6 h-6 top-1/2 rounded-full bg-gray-500 p-0.5 transform -translate-x-1/2 -translate-y-1/2 text-center">
|
||||
<i class="bi bi-images text-white text-center"></i>
|
||||
</button> */}
|
||||
<button onclick$={handleSubmit} class="absolute right-4 w-6 h-6 top-1/2 rounded-full bg-gray-500 p-0.5 transform -translate-x-1/2 -translate-y-1/2 text-center">
|
||||
<button class="absolute right-4 w-6 h-6 top-1/2 rounded-full bg-gray-500 p-0.5 transform -translate-x-1/2 -translate-y-1/2 text-center">
|
||||
<i class="bi bi-send text-white text-center"></i>
|
||||
</button>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { component$, useContext, useVisibleTask$ } from "@builder.io/qwik";
|
||||
import { type DocumentHead, routeLoader$, Link, useLocation } from "@builder.io/qwik-city";
|
||||
import axios from "axios";
|
||||
import RoomGrid from "~/components/room/RoomGrid";
|
||||
import { useContextProvider, useSignal, $ } from "@builder.io/qwik";
|
||||
import { useSignal, $ } from "@builder.io/qwik";
|
||||
import { AppStateContext } from "~/utils/context";
|
||||
import { getCookie } from "~/utils/cookie";
|
||||
import ShowRoomGrid from "~/components/room/ShowRoomGrid";
|
||||
interface FriendRequest {
|
||||
id: number;
|
||||
user_id: number;
|
||||
|
|
@ -13,42 +13,50 @@ interface FriendRequest {
|
|||
status: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
interface User {
|
||||
id: number;
|
||||
username: string;
|
||||
email: string;
|
||||
created_at: string;
|
||||
profile_image_path: string;
|
||||
is_active: boolean;
|
||||
}
|
||||
export const useDataLoader = routeLoader$(async ({params, cookie}) => {
|
||||
const headers = {
|
||||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
}
|
||||
try {
|
||||
// console.log(cookie.get("access_token")?.value + "이것은 토큰");
|
||||
const userid = await axios.get(`http://localhost:8000/api/user/profile/${params.username}`);
|
||||
// console.log(userid.data.id + "<- 이것은 아이디");
|
||||
const res = await axios.get(`http://localhost:8000/api/diary/w/{userid.data.id}?target_user_id=${userid.data.id}&skip=0&limit=6`, {
|
||||
|
||||
const user = await axios.get<User>(`http://localhost:8000/api/user/profile/${params.username}`);
|
||||
const [room, avatar, friendRequest, diaries] = await Promise.all([
|
||||
axios.get(`http://localhost:8000/api/room/layout/${user.data.id}`, { headers }),
|
||||
axios.get(`http://localhost:8000/api/avatar/${user.data.id}`, { headers }),
|
||||
axios.get(`http://localhost:8000/api/friendship/pending`, { headers }),
|
||||
axios.get(`http://localhost:8000/api/diary/w/${user.data.id}?skip=0&limit=6`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
},
|
||||
});
|
||||
const friendRequest = await axios.get(`http://localhost:8000/api/friendship/pending`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
},
|
||||
});
|
||||
const room = await axios.get(`http://localhost:8000/api/room/layout`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
},
|
||||
});
|
||||
const avatar = await axios.get(`http://localhost:8000/api/avatar`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
},
|
||||
});
|
||||
}),
|
||||
]);
|
||||
|
||||
// const avatar = await axios.get(`http://localhost:8000/api/avatar/${userid.data.id}`, {
|
||||
// headers: {
|
||||
// Authorization: `Bearer ${cookie.get("access_token")?.value}`,
|
||||
// },
|
||||
// });
|
||||
// console.log(res.data+ "다이어리 데이터 불러오기");
|
||||
// console.log("??/" + res.data.diaries);
|
||||
return {diaries: res.data, friendRequest: friendRequest.data as FriendRequest[], userdata: {room: room.data, avatar: avatar.data} };
|
||||
return {diaries: diaries.data, friendRequest: friendRequest.data as FriendRequest[], userdata: {room: room.data, avatar: avatar.data} };
|
||||
} catch (error : any) {
|
||||
console.error(error);
|
||||
console.error("에러 : " + error.config.url);
|
||||
return {diaries: [], friendRequest: [] as FriendRequest[], userdata: {room: [], avatar: [] } };
|
||||
}
|
||||
});
|
||||
export default component$(() => {
|
||||
const data = useDataLoader();
|
||||
console.log(data.value.userdata.avatar);
|
||||
const showMyFriendsRequest = useSignal<boolean>(false);
|
||||
const userData = useContext(AppStateContext);
|
||||
const selectedRoom = useSignal({});
|
||||
|
|
@ -90,6 +98,11 @@ export default component$(() => {
|
|||
<div>
|
||||
<div class="flex flex-col lg:flex-row gap-8">
|
||||
{/* <RoomGrid furniture={data.value.room} avatar={data.value.avatar} roomType={data.value.roomType} /> */}
|
||||
<ShowRoomGrid
|
||||
roomSrc={data.value.userdata.room.room.room_type}
|
||||
furnitures={data.value.userdata.room.furniture}
|
||||
avatars={data.value.userdata.avatar}
|
||||
/>
|
||||
<section class="mb-6 flex flex-col justify-between gap-8">
|
||||
<div class="flex-1">
|
||||
<h2 class="text-xl w-full pl-3 pb-1 font-bold border-b-2 border-[#4b3c28] inline-block mb-2">Update</h2>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue