Skip to content
Merged
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
2 changes: 1 addition & 1 deletion apps/api/src/controllers/teamController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,8 @@ export const updateTeamOrder = async (req: UpdateTeamOrderRequest, res: Response
update: { $set: { order: index } },
},
}));

await Team.bulkWrite(bulkOperations);

const reorderedTeams = await Team.find().sort({ order: 1 }).lean();

res.status(200).send({
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/models/teamModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export interface TeamDocument extends Omit<TeamType, "_id">, Document {}
const TeamSchema = new Schema<TeamDocument>(
{
name: { type: String, unique: true, required: true },
order: { type: Number, unique: true, required: false },
order: { type: Number },
},
{ timestamps: true, versionKey: false },
);
Expand Down
7 changes: 1 addition & 6 deletions apps/web/app/_components/AuthGuard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,15 @@

import { useEffect, useState } from "react";
import { PAGE_NAME } from "@ui/src/utils/constants/pageNames";
import { redirect, useRouter } from "next/navigation";
import { useRouter } from "next/navigation";
import { useAuthStore } from "@/app/store/useAuthStore";
import { useWebView } from "../_hooks/useWebView";
import SignInForm from "./SignInForm";

export default function AuthGuard(): JSX.Element | null {
const router = useRouter();
const [isLoading, setIsLoading] = useState(true);
const { isLoggedIn } = useAuthStore();

// 웹뷰 작업 추가
const { isWebView } = useWebView();
if (isWebView) redirect(PAGE_NAME.DASHBOARD);

useEffect(() => {
if (isLoggedIn) {
router.replace(PAGE_NAME.DASHBOARD);
Expand Down
6 changes: 4 additions & 2 deletions apps/web/app/_hooks/useAppRouter.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { useRouter } from "next/navigation";
import { WEBVIEW_MESSAGE_TYPES } from "@repo/constants";
import { sendMessageToNative } from "../utils/sendMessageToNative";
import { useWebView } from "./useWebView";
import { useDetectWebView } from "./useDetectWebView";

interface UseAppRouterResult {
push: (url: string) => void;
}

export const useAppRouter = (): UseAppRouterResult => {
const { isWebView } = useWebView();
const { isWebView } = useDetectWebView();
const router = useRouter();

const push = (url: string): void => {
// web view 실행
if (isWebView) {
sendMessageToNative({
type: WEBVIEW_MESSAGE_TYPES.ROUTER_EVENT,
Expand All @@ -20,6 +21,7 @@ export const useAppRouter = (): UseAppRouterResult => {
return;
}

// web 실행
router.push(url);
};

Expand Down
46 changes: 46 additions & 0 deletions apps/web/app/_hooks/useDetectWebView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useEffect, useState } from "react";

interface UseDetectWebViewResults {
isWebView: boolean;
isIOSWebView: boolean;
isAndroidWebView: boolean;
isIOS: boolean;
isAndroid: boolean;
}

export const useDetectWebView = (): UseDetectWebViewResults => {
const [result, setResult] = useState<UseDetectWebViewResults>({
isWebView: false,
isIOSWebView: false,
isAndroidWebView: false,
isIOS: false,
isAndroid: false,
});

useEffect(() => {
const userAgent = navigator.userAgent;

// IOS 웹뷰 감지
const isIOS = /iPhone|iPad|iPod/.test(userAgent);
const isWebKit = userAgent.includes("AppleWebKit");
const isSafari = userAgent.includes("Safari") || /Version\/[\d.]+.*Safari/.test(userAgent);
const isNotCriOS = !userAgent.includes("CriOS");
const isNotFxiOS = !userAgent.includes("FxiOS");

const isIOSWebView = isIOS && isWebKit && isNotCriOS && isNotFxiOS && !isSafari;

// Android 웹뷰 감지
const isAndroid = userAgent.includes("Android");
const isAndroidWebView = isAndroid && userAgent.includes("wv");

setResult({
isWebView: isIOSWebView || isAndroidWebView,
isIOSWebView,
isAndroidWebView,
isIOS,
isAndroid,
});
}, []);

return result;
};
21 changes: 0 additions & 21 deletions apps/web/app/_hooks/useWebView.ts

This file was deleted.

25 changes: 20 additions & 5 deletions apps/web/app/dashboard/_components/EmptyState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

import { TextBalloonIcon } from "@ui/public";
import Button from "@ui/src/components/common/Button";
import { useRouter } from "next/navigation";
import { PAGE_NAME } from "@ui/src/utils/constants/pageNames";
import Link from "next/link";
import { memo } from "react";
import { useDetectWebView } from "@/app/_hooks/useDetectWebView";
import { useAppRouter } from "@/app/_hooks/useAppRouter";

function EmptyState(): JSX.Element {
const router = useRouter();
const { push } = useAppRouter();
const { isWebView } = useDetectWebView();

const handleOnClick = (): void => {
router.push("/meetings");
const handleButtonClick = (): void => {
push(PAGE_NAME.MEETINGS);
};

return (
Expand All @@ -18,7 +22,18 @@ function EmptyState(): JSX.Element {
<TextBalloonIcon className="size-22" />
</span>
<p className="text-custom-black/80 text-15 mb-24">오늘 예정된 미팅이 없어요.</p>
<Button onClick={handleOnClick} variant="Secondary">
<Button
variant="Secondary"
as={isWebView ? "button" : Link}
{...(isWebView
? {
type: "button",
onClick: handleButtonClick,
}
: {
href: PAGE_NAME.MEETINGS,
})}
>
미팅 잡기
</Button>
</div>
Expand Down
4 changes: 2 additions & 2 deletions apps/web/app/settings/_components/SettingButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default function SettingButtons(): JSX.Element {
const options = useUserSettingOptions();
const { isOpen, currentModal: CurrentModal, openModal, closeModal } = useModal();

const handleOpenModal = (component: ModalComponentType<SettingsModalProps>): void => {
const handleClick = (component: ModalComponentType<SettingsModalProps>): void => {
openModal(component);
};

Expand All @@ -20,7 +20,7 @@ export default function SettingButtons(): JSX.Element {
className="text-lg-medium border-b-1 flex w-full items-center justify-between border-[#E8E8EA] px-8 py-20"
type="button"
onClick={() => {
handleOpenModal(component);
handleClick(component);
}}
>
{title}
Expand Down
4 changes: 2 additions & 2 deletions apps/web/components/Gnb/GnbMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { PAGE_NAME } from "@ui/src/utils/constants/pageNames";
import cn from "@ui/src/utils/cn";
import { Button } from "@ui/index";
import { useAppRouter } from "@/app/_hooks/useAppRouter";
import { useWebView } from "@/app/_hooks/useWebView";
import { useDetectWebView } from "@/app/_hooks/useDetectWebView";

const NAV_ITEMS = [
{ href: PAGE_NAME.DASHBOARD, name: "대시보드", icon: PersonIcon },
Expand All @@ -31,7 +31,7 @@ interface GnbMenuProps {
export default function GnbMenu({ isAdmin }: GnbMenuProps): JSX.Element | null {
const pathname = usePathname();
const { push } = useAppRouter();
const { isWebView } = useWebView();
const { isWebView } = useDetectWebView();

const handleButtonClick = (path: string): void => {
push(path);
Expand Down
1 change: 0 additions & 1 deletion apps/web/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
const nextConfig = {
reactStrictMode: true,
output: "export",
trailingSlash: true,

images: {
remotePatterns: [
Expand Down
Loading