Skip to content

Commit

Permalink
[Feature] QA 피드백 일부 반영 (#42)
Browse files Browse the repository at this point in the history
* fix: 팝업 로그인 일시적으로 뜨는 경우 해결

* fix: 팝업 로그인 관련 에러사항 수정

* fix: 바로가기 관련 에러 수정

* feat: 빈값 및 에러 관련 대응 추가

* fix: 팝업 로그인 관련 메세지 포스팅 추가

* fix: 로그아웃 노출 여부 수정

* feat: 중복 검색 기록 처리 로직 구현

* feat: 검색결과 클릭 인터랙션 추가

* fix: 빈 값 검색 불가 로직 추가
  • Loading branch information
cobocho authored Jul 25, 2024
1 parent ebd43dd commit 2ebc1a8
Show file tree
Hide file tree
Showing 16 changed files with 191 additions and 482 deletions.
95 changes: 57 additions & 38 deletions apps/extension/components/PopupBox/PopupBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,71 +2,80 @@
/* eslint-disable jsx-a11y/click-events-have-key-events */
import { Button, SymbolLogo, Text, TypoLogo } from '@vook-client/design-system'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { useLayoutEffect, useState } from 'react'
import { useEffect, useLayoutEffect, useState } from 'react'
import { baseFetcher, userOptions, vocabularyOptions } from '@vook-client/api'

import { getStorage, removeStorage, setStorage } from '../../utils/storage'
import { getStorage, removeStorage } from '../../utils/storage'

import { PopupBoxContainer } from './PopupBox.styles'

import { SearchBox } from 'components/SearchBox'

export const PopupBox = () => {
const [login, setLogin] = useState<boolean>(false)
const [tokenDone, setTokenDone] = useState<boolean>(false)
const [hasToken, setHasToken] = useState<boolean>(false)
const [initializing, setInitializing] = useState<boolean>(false)
const [hasResult, setHasResult] = useState<boolean>(false)

const client = useQueryClient()

const userInfo = useQuery({
const userInfoQuery = useQuery({
...userOptions.userInfo(client),
enabled: tokenDone,
enabled: hasToken,
})
const vocabularyQuery = useQuery({

useQuery({
...vocabularyOptions.vocabularyInfo(client),
enabled: tokenDone,
enabled: userInfoQuery.isSuccess,
})

useLayoutEffect(() => {
baseFetcher.setUnAuthorizedHandler(() => {
removeStorage('vook-access')
removeStorage('vook-refresh')
setTokenDone(false)
})
}, [])

useLayoutEffect(() => {
const setToken = async () => {
const access = await getStorage<string>('vook-access')
const refresh = await getStorage<string>('vook-refresh')
const vookLogin = await getStorage<string>('vook-login')

if (!access || !refresh) {
setTokenDone(false)
return
}

if (!vookLogin) {
setTokenDone(false)
setLogin(false)
setHasToken(false)
setInitializing(true)
return
}

client.setQueryData(['access'], access)
client.setQueryData(['refresh'], refresh)
setTokenDone(true)

setInitializing(true)
setHasToken(true)
}

setToken()
}, [client])

useLayoutEffect(() => {
if (userInfo.isSuccess && userInfo.data) {
setStorage('vook-user', userInfo.data)
setStorage('vook-vocabulary', vocabularyQuery.data)
setLogin(true)
}
}, [userInfo.data, userInfo.isSuccess, vocabularyQuery.data])
useEffect(() => {
window.addEventListener(
'message',
(event: {
data: {
from: string
access: string
refresh: string
}
}) => {
if (
event.data.from === 'vook-web' &&
event.data.access &&
event.data.refresh
) {
setHasToken(true)
}
},
)
}, [])

const onClickLogin = () => {
window.open(
Expand All @@ -76,28 +85,23 @@ export const PopupBox = () => {
)
}

if (!initializing) {
return null
}

const userInfo = userInfoQuery.data?.result || null

return (
<PopupBoxContainer
style={{
width: hasResult ? '800px' : '450px',
}}
>
<Button
size="small"
filled={false}
onClick={() => {
removeStorage('vook-access')
removeStorage('vook-refresh')
setLogin(false)
}}
>
로그아웃
</Button>
<div className="logo">
<SymbolLogo size={24} />
<TypoLogo size="small" />
</div>
{!login && (
{!hasToken && (
<>
<Text type="body-1" fontWeight="medium">
주제별로 용어집을 관리하고, 간편하게 용어를 검색하세요
Expand All @@ -121,7 +125,22 @@ export const PopupBox = () => {
</Text>
</>
)}
{login && <SearchBox hasResult={hasResult} setHasResult={setHasResult} />}
{userInfo && hasToken && (
<>
<Button
size="small"
filled={false}
onClick={() => {
removeStorage('vook-access')
removeStorage('vook-refresh')
setHasToken(false)
}}
>
로그아웃
</Button>
<SearchBox hasResult={hasResult} setHasResult={setHasResult} />
</>
)}
</PopupBoxContainer>
)
}
24 changes: 21 additions & 3 deletions apps/extension/components/SearchBox/SearchBox.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Icon, SymbolLogo } from '@vook-client/design-system'
import { Icon, SymbolLogo, Text } from '@vook-client/design-system'
import { useEffect, useState } from 'react'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { searchQueryOptions, vocabularyOptions } from '@vook-client/api'
Expand All @@ -23,7 +23,7 @@ export const SearchBox = ({ hasResult, setHasResult }: SearchBoxProps) => {
const query = useQuery({
...searchQueryOptions.search(
{
query: text,
queries: text.split(' '),
highlightPostTag: '</strong>',
highlightPreTag: '<strong>',
withFormat: true,
Expand All @@ -36,7 +36,9 @@ export const SearchBox = ({ hasResult, setHasResult }: SearchBoxProps) => {
})

const onSubmit = () => {
query.refetch()
if (text.trim().length > 0) {
query.refetch()
}
}

useEffect(() => {
Expand Down Expand Up @@ -71,6 +73,22 @@ export const SearchBox = ({ hasResult, setHasResult }: SearchBoxProps) => {
{query.isSuccess && (
<TermList records={query.data.result.records || []} />
)}
{query.data?.result.records.reduce((acc, cur) => {
return (acc += cur.hits.length)
}, 0) === 0 && (
<Text
type="body-1"
color="semantic-label-alternative"
fontWeight="medium"
>
검색 결과가 없습니다.
</Text>
)}
{query.isError && (
<Text type="body-1" color="status-error" fontWeight="medium">
검색 중 에러가 발생하였습니다.
</Text>
)}
</S.SearchBoxInputBox>
</S.SearchBoxContainer>
)
Expand Down
83 changes: 48 additions & 35 deletions apps/extension/components/SearchWindow/SearchWindow.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Text } from '@vook-client/design-system'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { searchQueryOptions, vocabularyOptions } from '@vook-client/api'

import { useSelectedText, useToggle } from '../../store/toggle'

import { SearchWindowHeader } from './SearchWindowHeader'
import * as S from './SearchWindow.styles'

import { useSearch } from 'hooks/useSearch'
import { TermList } from 'components/TermList'
import {
BlankTermList,
Expand Down Expand Up @@ -51,52 +52,72 @@ export const SearchWindow = () => {
const { selectedText } = useSelectedText()
const { position } = useToggle()

const { query, headerText, tailText } = useSearch({
selectedText,
const client = useQueryClient()

const vocabularyQuery = useQuery({
...vocabularyOptions.vocabularyInfo(client),
})

const searchQuery = useQuery({
...searchQueryOptions.search(
{
queries: selectedText,
highlightPostTag: '</strong>',
highlightPreTag: '<strong>',
withFormat: true,
vocabularyUids:
vocabularyQuery.data?.result.map((item) => item.uid) || [],
},
client,
),
enabled: vocabularyQuery.isSuccess && selectedText.length <= 10,
})

if (selectedText.length > 30) {
const External = () => {
return (
<a
href={process.env.PLASMO_PUBLIC_WEB_DOMAIN}
onClick={() => {
window.open(process.env.PLASMO_PUBLIC_WEB_DOMAIN, '_blank')
}}
style={{
cursor: 'pointer',
}}
>
Vook 바로가기
<LinkExternalIcon />
</a>
)
}

if (selectedText.length > 10) {
return (
<S.SearchWindowBox className="vook-search-window" position={position}>
<SearchWindowHeader />
<S.SearchOverMaxLength>
<Text color="label-alternative" type="body-2" fontWeight="medium">
용어 검색은 30자 이내로만 가능합니다.
용어 검색은 10단어 이내로만 가능합니다.
</Text>
</S.SearchOverMaxLength>
<S.SearchWindowLink>
<a
href={process.env.PLASMO_PUBLIC_WEB_DOMAIN}
target="_blank"
rel="noreferrer"
>
Vook 바로가기
<LinkExternalIcon />
</a>
<External />
</S.SearchWindowLink>
</S.SearchWindowBox>
)
}

if (query.isLoading) {
if (searchQuery.isLoading) {
return (
<S.SearchWindowBox className="vook-search-window" position={position}>
<SearchWindowHeader tailText="검색 중..." />
<S.SearchWindowLink>
<a
href={process.env.PLASMO_PUBLIC_WEB_DOMAIN}
target="_blank"
rel="noreferrer"
>
Vook 바로가기
<LinkExternalIcon />
</a>
<External />
</S.SearchWindowLink>
</S.SearchWindowBox>
)
}

if (query.isError) {
if (vocabularyQuery.isError || searchQuery.isError) {
return (
<S.SearchWindowBox className="vook-search-window" position={position}>
<SearchWindowHeader />
Expand All @@ -120,8 +141,7 @@ export const SearchWindow = () => {
}

if (
query.isSuccess &&
query.data.result.records.reduce(
searchQuery.data?.result.records.reduce(
(acc, record) => record.hits.length + acc,
0,
) === 0
Expand All @@ -143,28 +163,21 @@ export const SearchWindow = () => {
</SearchWindowBlankButton>
</BlankTermList>
<S.SearchWindowLink>
<a
href={process.env.PLASMO_PUBLIC_WEB_DOMAIN}
target="_blank"
rel="noreferrer"
>
Vook 바로가기
<LinkExternalIcon />
</a>
<External />
</S.SearchWindowLink>
</S.SearchWindowBox>
)
}

return (
<S.SearchWindowBox className="vook-search-window" position={position}>
<SearchWindowHeader headerText={headerText} tailText={tailText} />
<SearchWindowHeader />
<div
style={{
width: '800px',
}}
>
<TermList records={query.data?.result.records || []} />
<TermList records={searchQuery.data?.result.records || []} />
</div>
<S.SearchWindowLink>
<a
Expand Down
4 changes: 3 additions & 1 deletion apps/extension/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const getStyle = () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 3,
retry: 0,
},
},
})
Expand Down Expand Up @@ -91,8 +91,10 @@ function VookContentScript() {
await setStorage('vook-access', event.data.access)
await setStorage('vook-refresh', event.data.refresh)
await setStorage('vook-login', true)

queryClient.setQueryData(['access'], event.data.access)
queryClient.setQueryData(['refresh'], event.data.refresh)

postSuccessMessage()
}
},
Expand Down
Loading

0 comments on commit 2ebc1a8

Please sign in to comment.