Skip to content

Commit

Permalink
Merge pull request #273 from boostcampwm-2024/Feature/#269_workspace_…
Browse files Browse the repository at this point in the history
…관련_완성도_κ°œμ„ 

Feature/#269 workspace κ΄€λ ¨ 완성도 κ°œμ„ 
  • Loading branch information
github-actions[bot] authored Dec 2, 2024
2 parents 4373160 + 371ef7a commit d16ebd2
Show file tree
Hide file tree
Showing 13 changed files with 418 additions and 24 deletions.
43 changes: 43 additions & 0 deletions client/src/assets/icons/pencil.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions client/src/components/modal/RenameModal.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { css } from "@styled-system/css";

export const container = css({
display: "flex",
gap: "4",
flexDirection: "column",
});

export const title = css({
color: "gray.700",
fontSize: "lg",
fontWeight: "medium",
});

export const input = css({
borderColor: "gray.200",
borderRadius: "md",
borderWidth: "1px",
width: "full",
paddingY: "2",
paddingX: "3",
_focus: {
outline: "none",
borderColor: "blue.500",
},
_hover: {
borderColor: "gray.300",
},
});
41 changes: 41 additions & 0 deletions client/src/components/modal/RenameModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useState } from "react";
import { container, title, input } from "./RenameModal.style";
import { Modal } from "./modal";

interface RenameModalProps {
isOpen: boolean;
onClose: () => void;
onRename: (newName: string) => void;
currentName: string;
}

export const RenameModal = ({ isOpen, onClose, onRename, currentName }: RenameModalProps) => {
const [name, setName] = useState(currentName);

const handleRename = () => {
if (name.trim()) {
onRename(name);
onClose();
}
};

return (
<Modal
isOpen={isOpen}
primaryButtonLabel="λ³€κ²½ν•˜κΈ°"
primaryButtonOnClick={handleRename}
secondaryButtonLabel="μ·¨μ†Œ"
secondaryButtonOnClick={onClose}
>
<div className={container}>
<h2 className={title}>μ›Œν¬μŠ€νŽ˜μ΄μŠ€ 이름 λ³€κ²½</h2>
<input
className={input}
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="μƒˆλ‘œμš΄ μ›Œν¬μŠ€νŽ˜μ΄μŠ€ 이름"
/>
</div>
</Modal>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { css } from "@styled-system/css";

export const menuItemWrapper = css({
display: "flex",
gap: "md",
gap: "32px",
alignItems: "center",
width: "250px",
padding: "md",
Expand All @@ -15,6 +15,7 @@ export const menuItemWrapper = css({
export const textBox = css({
color: "gray.700",
fontSize: "md",
fontWeight: "medium",
});

export const menuButtonContainer = css({
Expand All @@ -24,7 +25,48 @@ export const menuButtonContainer = css({
top: "100%",
left: 0,
width: "100%",
height: "4px", // top: calc(100% + 4px)와 λ™μΌν•œ κ°’
height: "4px",
content: '""',
},
});

export const nameWrapper = css({
display: "flex",
gap: "1",
flexDirection: "column",
borderColor: "gray.200",
borderRadius: "md",
borderWidth: "1px",
padding: "sm",
borderStyle: "solid",
_hover: {
borderColor: "gray.300", // hover μ‹œ ν…Œλ‘λ¦¬ 색상 λ³€κ²½
},
});
export const workspaceInfo = css({
display: "flex",
gap: "0.5",
flexDirection: "column",
});

export const workspaceHeader = css({
display: "flex",
gap: "2",
alignItems: "center",
});

export const currentWorkspaceNameBox = css({
color: "gray.600",
fontSize: "sm",
fontWeight: "medium",
});

export const workspaceRole = css({
color: "gray.500",
fontSize: "xs",
});

export const userCount = css({
color: "gray.500",
fontSize: "xs",
});
25 changes: 23 additions & 2 deletions client/src/components/sidebar/components/menuButton/MenuButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@ import { useSocketStore } from "@src/stores/useSocketStore";
import { useToastStore } from "@src/stores/useToastStore";
import { useWorkspaceStore } from "@src/stores/useWorkspaceStore";
import { useUserInfo } from "@stores/useUserStore";
import { menuItemWrapper, textBox, menuButtonContainer } from "./MenuButton.style";
import {
menuItemWrapper,
textBox,
menuButtonContainer,
// userCount,
// currentWorkspaceNameBox,
// workspaceInfo,
// workspaceRole,
// nameWrapper,
} from "./MenuButton.style";
import { MenuIcon } from "./components/MenuIcon";
import { WorkspaceSelectModal } from "./components/WorkspaceSelectModal";

Expand All @@ -14,12 +23,15 @@ export const MenuButton = () => {
const [isOpen, setIsOpen] = useState(false);
const { socket, workspace } = useSocketStore();
const { addToast } = useToastStore();
const currentRole = useWorkspaceStore((state) => state.currentRole);
// const currentWorkspaceName = useWorkspaceStore((state) => state.currentWorkspaceName);
// const currentActiveUsers = useWorkspaceStore((state) => state.currentActiveUsers);
// const currentMemberCount = useWorkspaceStore((state) => state.currentMemberCount);
const {
isOpen: isInviteModalOpen,
openModal: openInviteModal,
closeModal: closeInviteModal,
} = useModal();
const currentRole = useWorkspaceStore((state) => state.currentRole);
const handleMenuClick = () => {
setIsOpen((prev) => !prev);
};
Expand Down Expand Up @@ -91,6 +103,7 @@ export const MenuButton = () => {
}
openInviteModal();
};

return (
<>
<button
Expand All @@ -101,6 +114,14 @@ export const MenuButton = () => {
<button className={menuItemWrapper}>
<MenuIcon />
<p className={textBox}>{name ?? "Nocta"}</p>
{/* <div className={nameWrapper}>
{currentWorkspaceName && currentRole && (
<div className={workspaceInfo}>
<span className={currentWorkspaceNameBox}>{currentWorkspaceName}</span>
<span className={workspaceRole}>{currentRole}</span>
</div>
)}
</div> */}
</button>
<WorkspaceSelectModal isOpen={isOpen} userName={name} onInviteClick={handleInviteModal} />
<InviteModal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { css } from "@styled-system/css";

export const itemContainer = css({
display: "flex",
position: "relative", // λΆ€λͺ¨ μš”μ†Œμ— relative μΆ”κ°€
justifyContent: "space-between",
alignItems: "center",
borderLeft: "3px solid transparent", // ν™œμ„±ν™”λ˜μ§€ μ•Šμ•˜μ„ λ•Œ border 곡간 확보
Expand All @@ -20,10 +21,36 @@ export const informBox = css({
alignItems: "center",
marginLeft: "14px",
});
export const pencilButton = css({
display: "flex",
position: "absolute", // relative λŒ€μ‹  absolute μ‚¬μš©
top: "50%", // 쀑앙 정렬을 μœ„ν•΄
right: "5%", // left λŒ€μ‹  right μ‚¬μš©
transform: "translateY(-50%)", // μ •ν™•ν•œ μ„Έλ‘œ 쀑앙 μ •λ ¬
justifyContent: "center",
alignItems: "center",
borderRadius: "6px",
padding: "1",
opacity: "0",
backgroundColor: "gray.200",
transition: "all",
_hover: {
backgroundColor: "gray.100",
},
_groupHover: {
opacity: "100",
},
"& svg": {
// SVG μŠ€νƒ€μΌ μΆ”κ°€
width: "4",
height: "4",
color: "green",
},
});
export const itemContent = css({
display: "flex",
flex: 1,
gap: "10",
gap: "4",
alignItems: "center",
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { WorkspaceListItem } from "@noctaCrdt/Interfaces"; // 이전에 λ§Œλ“  μΈν„°νŽ˜μ΄μŠ€ import
import { useState } from "react";
import PencilIcon from "@assets/icons/pencil.svg?react";
import { RenameModal } from "@src/components/modal/RenameModal";
import { useSocketStore } from "@src/stores/useSocketStore";
import { useToastStore } from "@src/stores/useToastStore";
import { useUserInfo } from "@src/stores/useUserStore";
import { useWorkspaceStore } from "@src/stores/useWorkspaceStore";
import {
pencilButton,
itemContainer,
itemContent,
itemIcon,
Expand All @@ -30,31 +34,60 @@ export const WorkspaceSelectItem = ({
const { workspace, switchWorkspace } = useSocketStore();
const { addToast } = useToastStore();
const setCurrentRole = useWorkspaceStore((state) => state.setCurrentRole);
const [isRenameModalOpen, setIsRenameModalOpen] = useState(false);
const { socket } = useSocketStore();
const setCurrentWorkspaceName = useWorkspaceStore((state) => state.setCurrentWorkspaceName);
const isActive = workspace?.id === id; // ν˜„μž¬ μ›Œν¬μŠ€νŽ˜μ΄μŠ€ 확인
const isOwner = role === "owner";
const handleClick = () => {
if (!isActive) {
switchWorkspace(userId, id);
setCurrentRole(role);
setCurrentWorkspaceName(name);
addToast(`μ›Œν¬μŠ€νŽ˜μ΄μŠ€(${name})에 μ ‘μ†ν•˜μ˜€μŠ΅λ‹ˆλ‹€.`);
}
};
const handleRename = (newName: string) => {
socket?.emit("workspace/rename", {
workspaceId: id,
newName,
});
};

return (
<button className={`${itemContainer} ${isActive ? activeItem : ""}`} onClick={handleClick}>
<div className={itemContent}>
<div className={itemIcon}>{name.charAt(0)}</div>
<div className={itemInfo}>
<span className={itemName}>{name}</span>
<div className={informBox}>
<span className={itemMemberCount}>{role}</span>
{memberCount !== undefined && (
<span className={itemRole}>
μ ‘μ†μžμˆ˜ {activeUsers} / {memberCount} λͺ…{" "}
</span>
)}
<div className="relative flex items-center group">
<button className={`${itemContainer} ${isActive ? activeItem : ""}`} onClick={handleClick}>
<div className={itemContent}>
<div className={itemIcon}>{name.charAt(0)}</div>
<div className={itemInfo}>
<span className={itemName}>{name}</span>
<div className={informBox}>
<span className={itemMemberCount}>{role}</span>
{memberCount !== undefined && (
<span className={itemRole}>
μ ‘μ†μžμˆ˜ {activeUsers} / {memberCount} λͺ…{" "}
</span>
)}
</div>
</div>
{isOwner && (
<button
onClick={() => setIsRenameModalOpen(true)}
className={pencilButton}
aria-label="μ›Œν¬μŠ€νŽ˜μ΄μŠ€ 이름 λ³€κ²½"
>
<PencilIcon />
</button>
)}
</div>
</div>
</button>
</button>

<RenameModal
isOpen={isRenameModalOpen}
onClose={() => setIsRenameModalOpen(false)}
onRename={handleRename}
currentName={name}
/>
</div>
);
};
Loading

0 comments on commit d16ebd2

Please sign in to comment.