Skip to content

Commit

Permalink
[Feature] 확장 프로그램 로그인 환경 구성
Browse files Browse the repository at this point in the history
* feat: 확장 프로그램 로그인 연결

* feat: 확장 프로그램 새창 로그인 통신 구현

* fix: 검색창 에러 수정

* fix: 온보딩을 항상 실행하도록 수정

* feat: 상황별 unAuthorizedHandler 로직 구현

* feat: 디자인 변경사항 반영

* feat: 토큰 동기화용 컴포넌트 추가

* fix: 로그인 관련 에러 수정
  • Loading branch information
cobocho authored Jul 18, 2024
1 parent eabad84 commit ad39852
Show file tree
Hide file tree
Showing 33 changed files with 883 additions and 244 deletions.
20 changes: 20 additions & 0 deletions apps/extension/components/PopupBox/PopupBox.styles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import styled from '@emotion/styled'

export const PopupBoxContainer = styled.div`
min-width: 450px;
max-width: 700px;
margin: 20px;
padding: 20px;
display: flex;
flex-direction: column;
gap: 20px;
justify-content: center;
align-items: center;
.logo {
display: flex;
align-items: center;
}
`
127 changes: 127 additions & 0 deletions apps/extension/components/PopupBox/PopupBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* 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 { baseFetcher, userOptions, vocabularyOptions } from '@vook-client/api'

import { getStorage, removeStorage, setStorage } 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 [hasResult, setHasResult] = useState<boolean>(false)

const client = useQueryClient()

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

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)
return
}

client.setQueryData(['access'], access)
client.setQueryData(['refresh'], refresh)
setTokenDone(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])

const onClickLogin = () => {
window.open(
`${process.env.PLASMO_PUBLIC_WEB_DOMAIN}/login`,
'popup',
'width=600,height=600',
)
}

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 && (
<>
<Text type="body-1" fontWeight="medium">
주제별로 용어집을 관리하고, 간편하게 용어를 검색하세요
</Text>
<Button fit="fill">무료로 시작</Button>
<Text
as="span"
type="body-2"
fontWeight="medium"
color="palette-gray-700"
>
이미 계정이 있으신가요?{' '}
<Text
type="body-2"
color="status-info"
fontWeight="bold"
onClick={onClickLogin}
>
로그인
</Text>
</Text>
</>
)}
{login && <SearchBox hasResult={hasResult} setHasResult={setHasResult} />}
</PopupBoxContainer>
)
}
1 change: 1 addition & 0 deletions apps/extension/components/PopupBox/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { PopupBox } from './PopupBox'
76 changes: 76 additions & 0 deletions apps/extension/components/SearchBox/SearchBox.styles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import styled from '@emotion/styled'

export const SearchBoxContainer = styled.form`
position: relative;
min-width: 400px;
width: fit-content;
width: 500px;
`

export const SearchBoxInputBox = styled.div`
position: relative;
box-sizing: border-box;
width: 100%;
padding: 0px;
`

export const SearchBoxInput = styled.input`
width: 100%;
height: 58px;
background: #ffffff;
border: 1px solid rgba(112, 115, 124, 0.22);
border-radius: 6px;
font-family: 'Pretendard';
font-style: normal;
font-weight: 500;
font-size: 16px;
line-height: 150%;
letter-spacing: -0.01em;
font-feature-settings: 'ss10' on;
padding-left: 70px;
box-sizing: border-box;
::placeholder {
color: rgba(22, 23, 25, 0.25);
}
`

export const SearchBoxIcon = styled.div`
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
height: 58px;
width: 70px;
z-index: 20;
`

export const SearchButton = styled.button`
display: flex;
justify-content: center;
align-items: center;
border: none;
background-color: transparent;
position: absolute;
top: 0;
right: 0;
height: 58px;
width: 70px;
cursor: pointer;
z-index: 20;
`
77 changes: 77 additions & 0 deletions apps/extension/components/SearchBox/SearchBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Icon, SymbolLogo } from '@vook-client/design-system'
import { useEffect, useState } from 'react'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { searchQueryOptions, vocabularyOptions } from '@vook-client/api'

import * as S from './SearchBox.styles'

import { TermList } from 'components/TermList'

interface SearchBoxProps {
hasResult: boolean
setHasResult: (value: boolean) => void
}

export const SearchBox = ({ hasResult, setHasResult }: SearchBoxProps) => {
const [text, setText] = useState<string>('')
const client = useQueryClient()

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

const query = useQuery({
...searchQueryOptions.search(
{
query: text,
highlightPostTag: '</strong>',
highlightPreTag: '<strong>',
withFormat: true,
vocabularyUids:
vocabularyQuery.data?.result.map((item) => item.uid) || [],
},
client,
),
enabled: false,
})

const onSubmit = () => {
query.refetch()
}

useEffect(() => {
if (query.isSuccess && query.data.result.records.length > 0) {
setHasResult(true)
} else {
setHasResult(false)
}
}, [query?.data?.result.records, query.isSuccess, setHasResult])

return (
<S.SearchBoxContainer
style={{
width: hasResult ? 'fit-content' : 'auto',
}}
onSubmit={(e) => {
e.preventDefault()
onSubmit()
}}
>
<S.SearchBoxIcon>
<SymbolLogo size={24} />
</S.SearchBoxIcon>
<S.SearchButton>
<Icon name="search-big" />
</S.SearchButton>
<S.SearchBoxInputBox>
<S.SearchBoxInput
placeholder="어떤 용어가 궁금하신가요?"
onChange={(e) => setText(e.target.value)}
/>
{query.isSuccess && (
<TermList records={query.data.result.records || []} />
)}
</S.SearchBoxInputBox>
</S.SearchBoxContainer>
)
}
1 change: 1 addition & 0 deletions apps/extension/components/SearchBox/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { SearchBox } from './SearchBox'
11 changes: 10 additions & 1 deletion apps/extension/components/SearchWindow/SearchWindow.styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export const SearchWindowBox = styled.div<{ position: Position }>`
padding: 16px;
width: 500px;
width: fit-content;
min-width: 415px;
border-radius: 6px;
Expand Down Expand Up @@ -61,3 +62,11 @@ export const SearchWindowLink = styled.div`
transform: translateY(1px);
}
`

export const SearchOverMaxLength = styled.div`
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
`
Loading

0 comments on commit ad39852

Please sign in to comment.