Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
37 changes: 25 additions & 12 deletions src/api/workspace/org.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,29 @@ import {
type TUpdateMemberRoleRequest,
type TUpdateMemberRoleResponse,
type TUpdateWorkspaceRequest,
type TUploadImageResponse,
type TWorkspace,
type TWorkspaceDetail,
type TWorkspaceMemberCount,
} from "@/types/workspace/workspace";

import { axiosInstance } from "@/lib/axiosInstance";

const buildWorkspaceFormData = (
request: Record<string, unknown>,
imageFile?: File | null,
) => {
const formData = new FormData();

formData.append(
"request",
new Blob([JSON.stringify(request)], { type: "application/json" }),
);
if (imageFile) {
formData.append("image", imageFile);
}
return formData;
};

export const getMyWorkspaces = async (): Promise<TWorkspace[]> => {
const { data } =
await axiosInstance.get<ICommonResponse<TMyOrgsData>>("/api/org/my");
Expand All @@ -29,9 +44,11 @@ export const getMyWorkspaces = async (): Promise<TWorkspace[]> => {
export const createWorkspace = async (
body: TCreateOrgRequest,
): Promise<TCreateOrgResponse> => {
const { imageFile, ...request } = body;
const formData = buildWorkspaceFormData(request, imageFile);
const { data } = await axiosInstance.post<
ICommonResponse<TCreateOrgResponse>
>("/api/org/create", body);
>("/api/org/create", formData);
return data.data;
};

Expand All @@ -49,22 +66,18 @@ export const updateWorkspace = async (
orgId: number,
body: TUpdateWorkspaceRequest,
): Promise<void> => {
await axiosInstance.patch<ICommonResponse<string>>(`/api/org/${orgId}`, body);
const { imageFile, ...request } = body;
const formData = buildWorkspaceFormData(request, imageFile);
await axiosInstance.patch<ICommonResponse<string>>(
`/api/org/${orgId}`,
formData,
);
};

export const deleteWorkspace = async (orgId: number): Promise<void> => {
await axiosInstance.delete<ICommonResponse<string>>(`/api/org/${orgId}`);
};

export const uploadImage = async (file: File): Promise<string> => {
const formData = new FormData();
formData.append("image", file);
const { data } = await axiosInstance.post<
ICommonResponse<TUploadImageResponse>
>(`/api/images/upload`, formData);
return data.data.url;
};

export const getWorkspaceMembers = async (
orgId: number,
cursor?: string | null,
Expand Down
13 changes: 2 additions & 11 deletions src/pages/workspace/Workspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ import WorkspaceEmptyState from "@/components/workspace/WorkspaceEmptyState";
import WorkspaceListError from "@/components/workspace/WorkspaceListError";
import WorkspaceListLoading from "@/components/workspace/WorkspaceListLoading";

import {
createWorkspace,
getMyWorkspaces,
uploadImage,
} from "@/api/workspace/org";
import { createWorkspace, getMyWorkspaces } from "@/api/workspace/org";
import PlusIcon from "@/assets/icon/common/plus.svg?react";
import SearchIcon from "@/assets/icon/common/search.svg?react";
import UpLoadImgIcon from "@/assets/icon/common/uploadImg.svg?react";
Expand Down Expand Up @@ -47,12 +43,7 @@ export default function WorkspacePage() {
mutationFn: async () => {
const name = newName.trim();
const description = newDesc.trim();
let logoUrl: string | null = null;

if (logoFile) {
logoUrl = await uploadImage(logoFile);
}
return createWorkspace({ name, description, logoUrl });
return createWorkspace({ name, description, imageFile: logoFile });
},

onSuccess: () => {
Expand Down
32 changes: 15 additions & 17 deletions src/pages/workspace/WorkspaceSetting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
deleteWorkspace,
getWorkspace,
updateWorkspace,
uploadImage,
} from "@/api/workspace/org";
import BuildingIcon from "@/assets/icon/common/building.svg?react";
import WarnIcon from "@/assets/icon/common/warn-circle.svg?react";
Expand Down Expand Up @@ -43,8 +42,8 @@ export default function WorkspaceSetting() {
const [serverLogoUrl, setServerLogoUrl] = useState<string | null>(null);
const [logoFile, setLogoFile] = useState<File | null>(null);
const [logoPreview, setLogoPreview] = useState<string | null>(null);
const [uploading, setUploading] = useState(false);
const [imageError, setImageError] = useState(false);
const [isImageDeleted, setIsImageDeleted] = useState(false);
const fileRef = useRef<HTMLInputElement | null>(null);

const fetchWorkspaceDetail = async () => {
Expand All @@ -61,6 +60,7 @@ export default function WorkspaceSetting() {
setDesc(detail.description ?? "");
setServerLogoUrl(detail.logoUrl ?? null);
setLogoFile(null);
setIsImageDeleted(false);
setLogoPreview((prev) => {
if (prev) URL.revokeObjectURL(prev);
return null;
Expand Down Expand Up @@ -88,17 +88,11 @@ export default function WorkspaceSetting() {
setSaving(true);

try {
let nextLogoUrl = serverLogoUrl ?? null;

if (logoFile) {
setUploading(true);
nextLogoUrl = await uploadImage(logoFile);
setUploading(false);
}
await updateWorkspace(orgId, {
name: nextName,
description: nextDesc,
logoUrl: nextLogoUrl,
imageFile: logoFile,
isImageDeleted,
});
toast.success("변경사항이 저장되었습니다");
await fetchWorkspaceDetail();
Comment thread
jjjsun marked this conversation as resolved.
Expand All @@ -108,7 +102,6 @@ export default function WorkspaceSetting() {
);
} finally {
setSaving(false);
setUploading(false);
}
};
const onDelete = async () => {
Expand Down Expand Up @@ -147,6 +140,8 @@ export default function WorkspaceSetting() {
if (!file) return;

setLogoFile(file);
setIsImageDeleted(false);

const previewUrl = URL.createObjectURL(file);
setLogoPreview((prev) => {
if (prev) URL.revokeObjectURL(prev);
Expand All @@ -162,6 +157,9 @@ export default function WorkspaceSetting() {

const onResetLogo = () => {
setLogoFile(null);
setIsImageDeleted(true);
setImageError(false);

setLogoPreview((prev) => {
if (prev) URL.revokeObjectURL(prev);
return null;
Expand Down Expand Up @@ -238,7 +236,7 @@ export default function WorkspaceSetting() {
className="h-7! border border-gray-200 text-text-auth-sub px-4 rounded-component-lg bg-white font-body2 hover:bg-gray-100 transition-colors duration-200 ease-in-out"
onClick={openFilePicker}
aria-label="로고 이미지 업로드 버튼"
disabled={saving || deleting || uploading}
disabled={saving || deleting}
>
업로드
</Button>
Expand All @@ -248,7 +246,7 @@ export default function WorkspaceSetting() {
className="h-7! border border-gray-200 text-text-auth-sub px-4 rounded-component-lg bg-white font-body2 hover:bg-gray-100 transition-colors duration-200 ease-in-out"
onClick={onResetLogo}
aria-label="로고 이미지 초기화 버튼"
disabled={saving || deleting || uploading}
disabled={saving || deleting}
>
초기화
</Button>
Expand All @@ -260,7 +258,7 @@ export default function WorkspaceSetting() {
value={name}
placeholder="조직의 이름 또는 워크스페이스 이름을 입력해주세요"
onChange={(e) => setName(e.target.value)}
disabled={saving || deleting || uploading}
disabled={saving || deleting}
/>
<TextareaField
id="workspace-setting-desc"
Expand All @@ -270,7 +268,7 @@ export default function WorkspaceSetting() {
onChange={(e) => setDesc(e.target.value)}
minRows={4}
className="min-h-90"
disabled={saving || deleting || uploading}
disabled={saving || deleting}
/>
</div>
</div>
Expand All @@ -280,7 +278,7 @@ export default function WorkspaceSetting() {
variant="primary"
type="button"
onClick={onSave}
disabled={!name.trim() || saving || deleting || uploading}
disabled={!name.trim() || saving || deleting}
aria-label="변경사항 저장하기"
className="w-auto tablet:w-full"
>
Expand All @@ -302,7 +300,7 @@ export default function WorkspaceSetting() {
buttonVariant="dangerSoft"
buttonSize="big"
buttonClassName="px-8 !rounded-component-md"
buttonDisabled={saving || deleting || uploading}
buttonDisabled={saving || deleting}
leadingSlot={<WarnIcon className="text-red-500 w-12 h-12" />}
/>
</div>
Expand Down
9 changes: 3 additions & 6 deletions src/types/workspace/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type TMyOrgsData = {
export type TCreateOrgRequest = {
name: string;
description: string;
logoUrl?: string | null;
imageFile?: File | null;
};

export type TCreateOrgResponse = {
Expand All @@ -39,11 +39,8 @@ export type TWorkspaceDetail = TGetOrgResponse;
export type TUpdateWorkspaceRequest = {
name: string;
description: string;
logoUrl: string | null;
};

export type TUploadImageResponse = {
url: string;
imageFile?: File | null;
isImageDeleted: boolean;
};

export type TWorkspaceMember = {
Expand Down
Loading