Skip to content
Open
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ dist
dist-ssr
*.local

# TypeScript incremental build cache
*.tsbuildinfo

# Editor directories and files
.vscode/*
!.vscode/extensions.json
Expand Down
22 changes: 11 additions & 11 deletions apps/pyconkr-2025/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useBackendClient, useFlattenSiteMapQuery, useSponsorQuery } from "@frontend/common/src/hooks/useAPI";
import { buildNestedSiteMap } from "@frontend/common/src/utils";
import * as React from "react";
import { useBackendClient, useFlattenSiteMapQuery, useSponsorQuery } from "@frontend/common/hooks/useAPI";
import { NestedSiteMapSchema } from "@frontend/common/schemas/backendAPI";
import { buildNestedSiteMap } from "@frontend/common/utils";
import { FC, useEffect } from "react";
import { Route, Routes, useLocation } from "react-router-dom";
import * as R from "remeda";
import { isEmpty, isNullish } from "remeda";

import * as BackendAPISchemas from "@frontend/common/src/schemas/backendAPI";
import MainLayout from "./components/layout/index.tsx";
import { PageIdParamRenderer, RouteRenderer } from "./components/pages/dynamic_route.tsx";
import { PresentationDetailPage } from "./components/pages/presentation_detail.tsx";
Expand All @@ -14,7 +14,7 @@ import { Test } from "./components/pages/test.tsx";
import { IS_DEBUG_ENV } from "./consts";
import { useAppContext } from "./contexts/app_context";

export const App: React.FC = () => {
export const App: FC = () => {
const backendAPIClient = useBackendClient();
const { data: sponsorTiers } = useSponsorQuery(backendAPIClient);
const { data: flatSiteMap } = useFlattenSiteMapQuery(backendAPIClient);
Expand All @@ -23,17 +23,17 @@ export const App: React.FC = () => {
const location = useLocation();
const { setAppContext, language } = useAppContext();

React.useEffect(() => {
useEffect(() => {
(async () => {
const currentRouteCodes = ["", ...location.pathname.split("/").filter((code) => !R.isEmpty(code))];
const currentSiteMapDepth: (BackendAPISchemas.NestedSiteMapSchema | undefined)[] = [siteMapNode];
const currentRouteCodes = ["", ...location.pathname.split("/").filter((code) => !isEmpty(code))];
const currentSiteMapDepth: (NestedSiteMapSchema | undefined)[] = [siteMapNode];

for (const routeCode of currentRouteCodes.splice(1)) {
const childrenMap = currentSiteMapDepth
.at(-1)
?.children?.reduce((acc, child) => ({ ...acc, [child.route_code]: child }), {} as Record<string, BackendAPISchemas.NestedSiteMapSchema>);
?.children?.reduce((acc, child) => ({ ...acc, [child.route_code]: child }), {} as Record<string, NestedSiteMapSchema>);
currentSiteMapDepth.push(childrenMap?.[routeCode]);
if (R.isNullish(currentSiteMapDepth.at(-1))) {
if (isNullish(currentSiteMapDepth.at(-1))) {
console.warn(`Route not found in site map: ${routeCode}`);
break;
}
Expand Down
12 changes: 5 additions & 7 deletions apps/pyconkr-2025/src/components/layout/BreadCrumb/index.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
import { NestedSiteMapSchema } from "@frontend/common/schemas/backendAPI";
import { Stack, styled } from "@mui/material";
import * as React from "react";
import { FC } from "react";
import { Link } from "react-router-dom";
import * as R from "remeda";

import { NestedSiteMapSchema } from "../../../../../../packages/common/src/schemas/backendAPI";

import { isNonNullish } from "remeda";
type BreadCrumbPropType = {
title: string;
parentSiteMaps: (NestedSiteMapSchema | undefined)[];
};

export const BreadCrumb: React.FC<BreadCrumbPropType> = ({ title, parentSiteMaps }) => {
export const BreadCrumb: FC<BreadCrumbPropType> = ({ title, parentSiteMaps }) => {
let route = "/";
return (
<BreadCrumbContainer>
<BreadcrumbPathContainer direction="row" alignItems="center">
{parentSiteMaps
.slice(1, -1)
.filter((routeInfo) => R.isNonNullish(routeInfo))
.filter((routeInfo) => isNonNullish(routeInfo))
.map(({ route_code, name }, index) => {
route += `${route_code}/`;
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as Shop from "@frontend/shop";
import { useCart, useShopClient } from "@frontend/shop/hooks";
import { ShoppingCart } from "@mui/icons-material";
import { Badge, badgeClasses, IconButton, styled } from "@mui/material";
import { ErrorBoundary, Suspense } from "@suspensive/react";
import * as React from "react";
import { FC } from "react";
import { useNavigate } from "react-router-dom";

type InnerCartBadgeButtonPropType = {
Expand All @@ -19,7 +19,7 @@ const ColoredIconButton = styled(IconButton)(({ theme }) => ({

const InnerCartBadge = styled(Badge)({ [`& .${badgeClasses.badge}`]: { top: "-12px", right: "-3px" } });

const InnerCartBadgeButton: React.FC<InnerCartBadgeButtonPropType> = ({ loading, count }) => {
const InnerCartBadgeButton: FC<InnerCartBadgeButtonPropType> = ({ loading, count }) => {
const navigate = useNavigate();

return (
Expand All @@ -30,11 +30,11 @@ const InnerCartBadgeButton: React.FC<InnerCartBadgeButtonPropType> = ({ loading,
);
};

export const CartBadgeButton: React.FC = Suspense.with(
export const CartBadgeButton: FC = Suspense.with(
{ fallback: <InnerCartBadgeButton loading /> },
ErrorBoundary.with({ fallback: <InnerCartBadgeButton /> }, () => {
const shopAPIClient = Shop.Hooks.useShopClient();
const { data: cart } = Shop.Hooks.useCart(shopAPIClient);
const shopAPIClient = useShopClient();
const { data: cart } = useCart(shopAPIClient);
return <InnerCartBadgeButton count={cart?.products.length} loading={false} />;
})
);
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import styled from "@emotion/styled";
import { useEmail } from "@frontend/common/src/hooks/useEmail";
import { useEmail } from "@frontend/common/hooks/useEmail";
import { Article, Email, Facebook, GitHub, Instagram, LinkedIn, X, YouTube } from "@mui/icons-material";
import * as React from "react";
import { FC } from "react";

import FlickrIcon from "@apps/pyconkr-2025/assets/thirdparty/flickr.svg?react";

import { useAppContext } from "../../../../contexts/app_context";
import { useAppContext } from "@apps/pyconkr-2025/contexts/app_context";

interface IconItem {
icon: React.FC<{ width?: number; height?: number }>;
icon: FC<{ width?: number; height?: number }>;
alt: string;
href: string;
}
Expand Down
15 changes: 7 additions & 8 deletions apps/pyconkr-2025/src/components/layout/Footer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import styled from "@emotion/styled";
import { useEmail } from "@frontend/common/src/hooks/useEmail";
import { useEmail } from "@frontend/common/hooks/useEmail";
import { Article, Email, Facebook, GitHub, Instagram, LinkedIn, OpenInNew, X, YouTube } from "@mui/icons-material";
import { Button, useMediaQuery, useTheme } from "@mui/material";
import * as React from "react";
import { FC, Fragment } from "react";

import FlickrIcon from "@apps/pyconkr-2025/assets/thirdparty/flickr.svg?react";
import { useAppContext } from "@apps/pyconkr-2025/contexts/app_context";

// import MobileFooter from "./Mobile/MobileFooter";
import { useAppContext } from "../../../contexts/app_context";
import MobileFooter from "./Mobile/MobileFooter";

interface IconItem {
icon: React.FC<{ width?: number; height?: number }>;
icon: FC<{ width?: number; height?: number }>;
alt: string;
href: string;
}
Expand Down Expand Up @@ -47,7 +46,7 @@ const defaultIcons: IconItem[] = [
},
];

const Bar: React.FC = () => <div style={{ display: "inline-block", padding: "0 0.25rem" }}>|</div>;
const Bar: FC = () => <div style={{ display: "inline-block", padding: "0 0.25rem" }}>|</div>;

export default function Footer() {
const { sendEmail } = useEmail();
Expand Down Expand Up @@ -119,12 +118,12 @@ export default function Footer() {
</FooterText>
<FooterLinks>
{links.map((link, index) => (
<React.Fragment key={index}>
<Fragment key={index}>
<Link key={link.text} href={link.href}>
{link.text}
</Link>
{index < links.length - 1 && <Separator>|</Separator>}
</React.Fragment>
</Fragment>
))}
</FooterLinks>
<FooterIcons>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { IconButton, styled } from "@mui/material";
import * as React from "react";

import { FC } from "react";
interface HamburgerButtonProps {
isOpen: boolean;
onClick: () => void;
isMainPath?: boolean;
}

export const HamburgerButton: React.FC<HamburgerButtonProps> = ({ isOpen, onClick, isMainPath = true }) => {
export const HamburgerButton: FC<HamburgerButtonProps> = ({ isOpen, onClick, isMainPath = true }) => {
return (
<StyledIconButton onClick={onClick} isMainPath={isMainPath}>
<HamburgerIcon isOpen={isOpen} isMainPath={isMainPath}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import { Components } from "@frontend/common";
import { PythonKorea } from "@frontend/common/components";
import { Box, Stack, styled, Typography } from "@mui/material";
import * as React from "react";
import { FC, useState } from "react";
import { Link, useLocation } from "react-router-dom";

import { useAppContext } from "@apps/pyconkr-2025/contexts/app_context";

import { HamburgerButton } from "./HamburgerButton";
import { MobileLanguageToggle } from "./MobileLanguageToggle";
import { MobileNavigation } from "./MobileNavigation";
import { useAppContext } from "../../../../contexts/app_context";

interface MobileHeaderProps {
isNavigationOpen?: boolean;
onToggleNavigation?: () => void;
}

export const MobileHeader: React.FC<MobileHeaderProps> = ({ isNavigationOpen = false, onToggleNavigation }) => {
export const MobileHeader: FC<MobileHeaderProps> = ({ isNavigationOpen = false, onToggleNavigation }) => {
const { siteMapNode } = useAppContext();
const location = useLocation();
const [internalNavigationOpen, setInternalNavigationOpen] = React.useState(false);
const [internalNavigationOpen, setInternalNavigationOpen] = useState(false);

const navigationOpen = onToggleNavigation ? isNavigationOpen : internalNavigationOpen;
const toggleNavigation = onToggleNavigation || (() => setInternalNavigationOpen(!internalNavigationOpen));
Expand All @@ -31,7 +32,7 @@ export const MobileHeader: React.FC<MobileHeaderProps> = ({ isNavigationOpen = f
<LogoAndTextContainer>
<Link to="/" style={{ textDecoration: "none" }}>
<Stack direction="row" alignItems="center" spacing={0.375}>
<Components.PythonKorea style={{ width: 29, height: 29 }} />
<PythonKorea style={{ width: 29, height: 29 }} />
<Typography
variant="h6"
sx={{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { ButtonBase, styled } from "@mui/material";
import * as React from "react";
import { FC } from "react";

import { LOCAL_STORAGE_LANGUAGE_KEY } from "../../../../consts/local_stroage";
import { useAppContext } from "../../../../contexts/app_context";
import { LOCAL_STORAGE_LANGUAGE_KEY } from "@apps/pyconkr-2025/consts/local_stroage";
import { useAppContext } from "@apps/pyconkr-2025/contexts/app_context";

interface MobileLanguageToggleProps {
isMainPath?: boolean;
}

export const MobileLanguageToggle: React.FC<MobileLanguageToggleProps> = ({ isMainPath = true }) => {
export const MobileLanguageToggle: FC<MobileLanguageToggleProps> = ({ isMainPath = true }) => {
const { language, setAppContext } = useAppContext();

const toggleLanguage = () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { Components } from "@frontend/common";
import * as BackendAPISchemas from "@frontend/common/src/schemas/backendAPI";
import { PythonKorea } from "@frontend/common/components";
import { NestedSiteMapSchema } from "@frontend/common/schemas/backendAPI";
import { ArrowBack, ArrowForward } from "@mui/icons-material";
import { Box, Button, Chip, Drawer, IconButton, Stack, styled, Typography } from "@mui/material";
import * as React from "react";
import { FC, useState } from "react";
import { Link, useLocation } from "react-router-dom";
import * as R from "remeda";
import { isEmpty } from "remeda";

import { SignInButton } from "@apps/pyconkr-2025/components/layout/SignInButton";

import { HamburgerButton } from "./HamburgerButton";
import { MobileLanguageToggle } from "./MobileLanguageToggle";
import { SignInButton } from "../../SignInButton";
// import { ScanCodeButton } from "../../UserScanCodeButton";
// import { ScanCodeButton } from "@apps/pyconkr-2025/components/layout/UserScanCodeButton";

type MenuType = BackendAPISchemas.NestedSiteMapSchema;
type MenuType = NestedSiteMapSchema;

interface MobileNavigationProps {
isOpen: boolean;
Expand All @@ -28,9 +29,9 @@ interface NavigationState {
breadcrumbs: { name: string; level: NavigationLevel }[];
}

export const MobileNavigation: React.FC<MobileNavigationProps> = ({ isOpen, onClose, siteMapNode }) => {
export const MobileNavigation: FC<MobileNavigationProps> = ({ isOpen, onClose, siteMapNode }) => {
const location = useLocation();
const [navState, setNavState] = React.useState<NavigationState>({
const [navState, setNavState] = useState<NavigationState>({
level: "depth1",
breadcrumbs: [],
});
Expand Down Expand Up @@ -88,7 +89,7 @@ export const MobileNavigation: React.FC<MobileNavigationProps> = ({ isOpen, onCl
.filter((s) => !s.hide)
.map((menu) => (
<MenuItem isMainPath={isMainPath} key={menu.id}>
{!R.isEmpty(menu.children) && Object.values(menu.children).some((child) => !child.hide) ? (
{!isEmpty(menu.children) && Object.values(menu.children).some((child) => !child.hide) ? (
<MenuButton isMainPath={isMainPath} onClick={() => navigateToDepth2(menu)}>
{menu.name}
</MenuButton>
Expand All @@ -97,7 +98,7 @@ export const MobileNavigation: React.FC<MobileNavigationProps> = ({ isOpen, onCl
{menu.name}
</MenuLink>
)}
{!R.isEmpty(menu.children) && Object.values(menu.children).some((child) => !child.hide) && (
{!isEmpty(menu.children) && Object.values(menu.children).some((child) => !child.hide) && (
<MenuArrowButton isMainPath={isMainPath} onClick={() => navigateToDepth2(menu)}>
<ArrowForward fontSize="small" />
</MenuArrowButton>
Expand Down Expand Up @@ -130,7 +131,7 @@ export const MobileNavigation: React.FC<MobileNavigationProps> = ({ isOpen, onCl
<Link to={`${navState.depth1!.route_code}/${menu.route_code}`} onClick={handleClose} style={{ textDecoration: "none" }}>
<MenuChip isMainPath={isMainPath} label={menu.name} clickable />
</Link>
{!R.isEmpty(menu.children) && Object.values(menu.children).some((child) => !child.hide) && (
{!isEmpty(menu.children) && Object.values(menu.children).some((child) => !child.hide) && (
<MenuArrowButton isMainPath={isMainPath} onClick={() => navigateToDepth3(menu)}>
<ArrowForward fontSize="small" />
</MenuArrowButton>
Expand Down Expand Up @@ -183,7 +184,7 @@ export const MobileNavigation: React.FC<MobileNavigationProps> = ({ isOpen, onCl
<LogoAndTextContainer>
<Link to="/" onClick={handleClose} style={{ textDecoration: "none" }}>
<Stack direction="row" alignItems="center" spacing={0.375}>
<Components.PythonKorea style={{ width: 29, height: 29 }} />
<PythonKorea style={{ width: 29, height: 29 }} />
<HeaderTitle isMainPath={isMainPath}>파이콘 한국 2025</HeaderTitle>
</Stack>
</Link>
Expand Down
Loading