Skip to content

Commit

Permalink
Merge pull request #156 from prgrms-web-devcourse-final-project/154-f…
Browse files Browse the repository at this point in the history
…eature/enhance-ux

[Feature] #154 UX 개선
  • Loading branch information
shlee9999 authored Dec 9, 2024
2 parents ec0a58d + 2a64959 commit 43c5ef8
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 65 deletions.
7 changes: 2 additions & 5 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { Suspense, useState } from 'react'
import { useState } from 'react'
import { Helmet, HelmetProvider } from 'react-helmet-async'
import { RouterProvider } from 'react-router-dom'
import styled, { ThemeProvider } from 'styled-components'
import PWABadge from '~/PWABadge'
import { router } from '~/router'
import GlobalStyle from '~/styles/globalStyle'
import { darkTheme, lightTheme } from '~/styles/theme'
import PageLoader from '~components/PageLoader'
import PushNotification from '~components/PushNotification'

const queryClient = new QueryClient()
Expand All @@ -31,9 +30,7 @@ function App() {
</button>
<GlobalStyle />
<MobileContainer>
<Suspense fallback={<PageLoader />}>
<RouterProvider router={router} />
</Suspense>
<RouterProvider router={router} />
<PushNotification />
</MobileContainer>
<PWABadge />
Expand Down
13 changes: 13 additions & 0 deletions src/assets/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/components/Footer/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const Footer = styled.footer`
bottom: 0;
background-color: ${({ theme }) => theme.colors.grayscale.gc_4};
box-shadow: inset 0 1px 0 0 ${({ theme }) => theme.colors.grayscale.gc_1};
z-index: 900;
`

export const FooterNavList = styled.ul`
Expand Down
2 changes: 2 additions & 0 deletions src/components/GlobalHookContainer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { ReactNode } from 'react'
import useClearModal from '~hooks/useClearModal'
import useSubscribe from '~hooks/useSubscribe'
import useToken from '~hooks/useToken'

export default function GlobalHookContainer({ children }: { children: ReactNode }) {
useToken()
useSubscribe()
useClearModal()
return <>{children}</>
}
2 changes: 1 addition & 1 deletion src/components/SendMessageForm/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const SendMessageForm = styled.form`
display: flex;
align-items: center;
gap: 12px;
z-index: 1;
z-index: 1000;
`
export const ChatInput = styled.input`
flex: 1;
Expand Down
11 changes: 11 additions & 0 deletions src/hooks/useClearModal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useEffect } from 'react'
import { useLocation } from 'react-router-dom'
import { useModalStore } from '~stores/modalStore'

export default function useClearModal() {
const { pathname } = useLocation()
const { clearModal } = useModalStore()
useEffect(() => {
clearModal()
}, [pathname])

Check warning on line 10 in src/hooks/useClearModal.ts

View workflow job for this annotation

GitHub Actions / lighthouse

React Hook useEffect has a missing dependency: 'clearModal'. Either include it or remove the dependency array
}
12 changes: 12 additions & 0 deletions src/modals/ChatArea/styles.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
import { styled } from 'styled-components'
import DogHowling from '~assets/dog_howling.svg'

export const ChatArea = styled.div`
position: relative;
height: calc(100% - 64px);
overflow: auto;
&::after {
background: url(${DogHowling}) center/cover;
content: '';
width: 190px;
height: 260px;
position: fixed;
bottom: 95px;
left: 50%;
translate: -50%;
}
`
export const ChatMessageList = styled.div``
12 changes: 1 addition & 11 deletions src/modals/ChatModal/styles.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,14 @@
import { styled } from 'styled-components'
import { HEADER_HEIGHT_LG } from '~constants/layout'
import DogHowling from '~assets/dog_howling.svg'

export const ChatModal = styled.div`
position: relative;
width: 100%;
height: 100%;
padding: ${HEADER_HEIGHT_LG}px 20px 0;
background-color: ${({ theme }) => theme.colors.brand.lighten_3};
&::after {
background: url(${DogHowling}) center/cover;
content: '';
width: 190px;
height: 260px;
position: fixed;
bottom: 95px;
left: 50%;
translate: -50%;
}
`

export const ProfileWrapper = styled.div`
display: flex;
align-items: center;
Expand Down
62 changes: 26 additions & 36 deletions src/modals/WalkAnalysisModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { useEffect, useRef, Suspense } from 'react'
import { useEffect, useRef } from 'react'
import { FamilyMemberWalk } from '~apis/log/fetchFamilyYearlyWalks'
import Prev from '~assets/prev.svg'
import { useCurrentMonthWalks, useFamilyWalks, useMonthlyWalks, useTotalWalks } from '~pages/LogPage/useWalkInfo'
import { useModalStore } from '~stores/modalStore'
import Statistics from './components/Statistics'
import { createBarChart, createLineChart } from './createChart'
import * as S from './styles'
import { FamilyMemberWalk } from '~apis/log/fetchFamilyYearlyWalks'
import Statistics from './components/Statistics'
import { useCurrentMonthWalks, useFamilyWalks, useMonthlyWalks, useTotalWalks } from '~pages/LogPage/useWalkInfo'
import { QueryErrorResetBoundary } from '@tanstack/react-query'
import { ErrorBoundary } from 'react-error-boundary'
import ErrorFallback from '~components/ErrorFallback'
import PageLoader from '~components/PageLoader'

interface ChartData {
month: string
Expand Down Expand Up @@ -55,33 +51,27 @@ export default function WalkAnalysisModal() {
}
}, [monthlyWalks, familyWalks])
return (
<QueryErrorResetBoundary>
{({ reset }) => (
<ErrorBoundary FallbackComponent={ErrorFallback} onReset={reset}>
<Suspense fallback={<PageLoader />}>
<S.Header>
<S.PrevBtn src={Prev} alt='뒤로 가기' onClick={popModal} />
<S.Title>산책 분석</S.Title>
</S.Header>
<S.WalkAnalysisModal>
<S.ChartArea>
<S.ChartWrapper>
<S.ChartTitle>올해 월 별 산책기록</S.ChartTitle>
<S.Chart ref={lineChartRef} width='100%' height='100%'></S.Chart>
</S.ChartWrapper>
<S.ChartWrapper>
<S.ChartTitle>올해 가족별 산책 횟수</S.ChartTitle>
<S.Chart ref={barChartRef} width='100%' height='100%'></S.Chart>
</S.ChartWrapper>
</S.ChartArea>
<S.StatisticsArea>
<Statistics title={'총 산책 내역'} stats={totalWalks} />
<Statistics title={'이번달 통계'} stats={currentMonthWalks} />
</S.StatisticsArea>
</S.WalkAnalysisModal>
</Suspense>
</ErrorBoundary>
)}
</QueryErrorResetBoundary>
<>
<S.Header>
<S.PrevBtn src={Prev} alt='뒤로 가기' onClick={popModal} />
<S.Title>산책 분석</S.Title>
</S.Header>
<S.WalkAnalysisModal>
<S.ChartArea>
<S.ChartWrapper>
<S.ChartTitle>올해 월 별 산책기록</S.ChartTitle>
<S.Chart ref={lineChartRef} width='100%' height='100%'></S.Chart>
</S.ChartWrapper>
<S.ChartWrapper>
<S.ChartTitle>올해 가족별 산책 횟수</S.ChartTitle>
<S.Chart ref={barChartRef} width='100%' height='100%'></S.Chart>
</S.ChartWrapper>
</S.ChartArea>
<S.StatisticsArea>
<Statistics title={'총 산책 내역'} stats={totalWalks} />
<Statistics title={'이번달 통계'} stats={currentMonthWalks} />
</S.StatisticsArea>
</S.WalkAnalysisModal>
</>
)
}
7 changes: 6 additions & 1 deletion src/pages/HomePage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { FAMILY_ROLE } from '~constants/familyRole'
import NotificationModal from '~modals/NotificationModal'
import { useModalStore } from '~stores/modalStore'
import * as S from './styles'
import { getParticle } from '~utils/getParticle'

function HomeContent() {
const {
Expand All @@ -40,7 +41,11 @@ function HomeContent() {
</S.Header>
<S.Visual>
<Typo24 $weight='700' $textAlign='center'>
오늘은 {data?.familyRole ? FAMILY_ROLE[data.familyRole] : ''}
오늘은{' '}
<Typo24 as='span' $color='default' $weight='700'>
{FAMILY_ROLE[data?.familyRole]}
</Typo24>
{getParticle(FAMILY_ROLE[data?.familyRole])}
</Typo24>
<Typo24 $weight='700' $textAlign='center'>
산책가는 날!
Expand Down
15 changes: 14 additions & 1 deletion src/pages/LogPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,20 @@ export default function LogPage() {
<S.GraphImage
src={GraphIcon}
alt='산책 기록 그래프'
onClick={() => pushModal(<WalkAnalysisModal />, 'slideLeft')}
onClick={() =>
pushModal(
<QueryErrorResetBoundary>
{({ reset }) => (
<ErrorBoundary FallbackComponent={ErrorFallback} onReset={reset}>
<Suspense fallback={<PageLoader />}>
<WalkAnalysisModal />
</Suspense>
</ErrorBoundary>
)}
</QueryErrorResetBoundary>,
'slideLeft'
)
}
/>
</Header>
<S.CalendarWrapper>
Expand Down
6 changes: 4 additions & 2 deletions src/pages/LoginPage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as S from './styles'
import { Helmet } from 'react-helmet-async'

import Logo from '~assets/favicon.svg?react'
const serverUrl = import.meta.env.VITE_SERVER_URL
const BACK_URL = new URL(serverUrl).origin

Expand Down Expand Up @@ -56,7 +56,9 @@ export default function LoginPage() {
<meta name='description' content='DDang 서비스 로그인' />
</Helmet>
<TitleSection />
<S.Logo>로고</S.Logo>
<S.Logo>
<Logo width='90%' height='90%' />
</S.Logo>
<SocialLoginButtons />
</S.LoginPage>
)
Expand Down
20 changes: 12 additions & 8 deletions src/router.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { Suspense } from 'react'
import { createBrowserRouter, Outlet } from 'react-router-dom'
import { WebSocketProvider } from '~/WebSocketContext'
import Footer from '~components/Footer'
import GlobalHookContainer from '~components/GlobalHookContainer'
import PageLoader from '~components/PageLoader'
import ModalContainer from '~modals/ModalContainer'
import * as Pages from './components/LazyComponents'
import GlobalHookContainer from '~components/GlobalHookContainer'

export const router = createBrowserRouter([
{
path: '/',
element: (
<WebSocketProvider>
<GlobalHookContainer>
<Outlet />
<Suspense fallback={<PageLoader />}>
<Outlet />
</Suspense>
<Footer />
<ModalContainer />
</GlobalHookContainer>
Expand Down Expand Up @@ -59,28 +63,28 @@ export const router = createBrowserRouter([
{
path: '/login',
element: (
<>
<Suspense fallback={<PageLoader />}>
<Pages.LoginPage />
<ModalContainer />
</>
</Suspense>
),
},
{
path: '/register',
element: (
<>
<Suspense fallback={<PageLoader />}>
<Pages.RegisterPage />
<ModalContainer />
</>
</Suspense>
),
},
{
path: '/register/dog',
element: (
<>
<Suspense fallback={<PageLoader />}>
<Pages.RegisterDogPage />
<ModalContainer />
</>
</Suspense>
),
},
])
18 changes: 18 additions & 0 deletions src/utils/getParticle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* word에 받침이 있으면 "이랑"
* 받침이 없으면 "랑" 반환
*/
export function getParticle(word: string) {
const lastChar = word.charAt(word.length - 1)
const unicodeValue = lastChar.charCodeAt(0)

// 한글 유니코드 범위 체크
if (unicodeValue < 0xac00 || unicodeValue > 0xd7a3) {
return word + '랑'
}

// 종성 확인
const hasConsonantJongseong = (unicodeValue - 0xac00) % 28 > 0

return hasConsonantJongseong ? '이랑' : '랑'
}

0 comments on commit 43c5ef8

Please sign in to comment.