Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
736fe30
🐛 시즌3 업데이트 어빌리티 스톤 관련 이슈 해결
EthanJcoding Jul 11, 2024
225d2ed
Merge branch 'dev' into feat/charCollection
EthanJcoding Jul 12, 2024
3512b2d
🎨 대쉬보드 링크 절대 경로로 변경
EthanJcoding Jul 12, 2024
d5ad9bd
♻️ Armory 인터페이스 리펙토링
EthanJcoding Jul 13, 2024
a4b107d
♻️ 인터페이스 리펙토링 적용
EthanJcoding Jul 13, 2024
8d6d12d
✨ 캐릭터 검색 페이지 제작
EthanJcoding Jul 14, 2024
d13e870
📱 헤더링크 반응형 수정
EthanJcoding Jul 14, 2024
17d68ca
🏷️ 인터페이스 업데이트
EthanJcoding Jul 14, 2024
44cb507
🎨 시간 유틸 함수 날짜 계산 기능추가
EthanJcoding Jul 14, 2024
deb8866
🏷️ 인터페이스 업데이트
EthanJcoding Jul 14, 2024
d7b6dd3
✨ 유저 검색 페이지 메타데이터 추가
EthanJcoding Jul 14, 2024
766ff7a
✨ header 모바일 환경 매뉴 버튼 제작
EthanJcoding Jul 15, 2024
456ef72
🐛 Gnb dashboardUrl 빈 문자열 버그 수정
EthanJcoding Jul 15, 2024
f278f24
📱 캐릭터 디테일 반응형 디자인 수정
EthanJcoding Jul 15, 2024
4a5c2a2
🎨 화면을 벗어나면 store 초기화 하는 클린업 함수 추가
EthanJcoding Jul 15, 2024
e255bea
🎨 코드 상수값 수정
EthanJcoding Jul 15, 2024
08ea962
📱 유저 검색 컴포넌트 반응형 수정
EthanJcoding Jul 15, 2024
6967bbc
🎨 모바일 대시보드 링크 수정 및 백그라운드 투명도값 조정
EthanJcoding Jul 15, 2024
04bd5ef
💄 초기 검색 화면 디자인 수정ㅈ
EthanJcoding Jul 15, 2024
8d0fdf9
💄 padding 값 통일화
EthanJcoding Jul 15, 2024
12e768f
🎨 최근 검색어 및 원대 리스트 접기 기능 추가
EthanJcoding Jul 15, 2024
0b6acbb
🎨 최근 검색어 접기 기능 추가
EthanJcoding Jul 15, 2024
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
41 changes: 41 additions & 0 deletions src/api/firebase/searchCharacter/searchCharacter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { doc, getDoc, setDoc } from 'firebase/firestore'
import { firestore } from '../config'
import { getCharacterData } from '@/api/lostark/getCharacterData'
import { customDateString } from '@/utils/customDateString'

async function searchCharacter(character: string) {
const characterRef = doc(firestore, 'characters', character)

try {
const docSnapshot = await getDoc(characterRef)

if (docSnapshot.exists()) {
const data = docSnapshot.data()
const lastUpdated = new Date(data.updated)
const oneDayAgo = new Date(customDateString(1))

if (lastUpdated < oneDayAgo) {
// 데이터가 1일 이상 지났으면 업데이트
const newData = await getCharacterData(character)
await setDoc(characterRef, { ...newData, updated: customDateString() })
return newData
} else {
// 데이터가 최신이면 그대로 반환
return data // 데이터 구조에 따라 'newData' 필드가 없다면 그냥 'data'를 반환
}
} else {
// 데이터가 없으면 새로 가져와서 저장
const newData = await getCharacterData(character)

if (newData) {
await setDoc(characterRef, { ...newData, updated: customDateString() })
return newData
} else return null
}
} catch (err) {
console.error('Error in searchCharacter:', err)
throw err // 오류를 상위로 전파
}
}

export { searchCharacter }
6 changes: 5 additions & 1 deletion src/api/lostark/getCharacterData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ export const getCharacterData = async (chaName: string) => {
}
)

return data.data
if (data) {
return data.data
} else {
console.log('not able to load character data:', data)
}
} catch (err) {
console.error(err)
}
Expand Down
2 changes: 1 addition & 1 deletion src/app/[channelId]/schedule/[scheduleId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default async function ScheduleDetail({ params }: Ownprops) {
const userData = await getServerSession(authOptions)

return (
<div className='max-w-[121rem] flex-1 flex flex-col gap-4 sm:flex-row h-full overflow-auto'>
<div className='max-w-[121rem] flex-1 flex flex-col gap-4 lg:flex-row h-full overflow-auto'>
<Raid userData={userData} scheduleId={scheduleId} />
</div>
)
Expand Down
37 changes: 37 additions & 0 deletions src/app/characters/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Header from '@/components/landing/header/Header'
import Search from '@/components/search/Search'
import { authOptions } from '@/utils/authOptions'
import { getServerSession, Session } from 'next-auth'

interface Ownprops {
searchParams: {
query: string
}
}

export async function generateMetadata({ searchParams }: Ownprops) {
const characterName = searchParams.query

if (!characterName) {
return {
title: `로레디 - 유저 검색`,
description: '로스트아크의 유저 정보를 확인할 수 있습니다.'
}
}

return {
title: `${characterName} - 유저 검색`,
description: '로스트아크의 유저 정보를 확인할 수 있습니다.'
}
}

export default async function Characters() {
const session = (await getServerSession(authOptions)) as Session

return (
<div className='w-full p-7 space-y-4 h-dvh flex flex-col bg-light dark:bg-dark dark:text-light max-sm:p-5'>
<Header session={session} />
<Search />
</div>
)
}
8 changes: 6 additions & 2 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { Metadata } from 'next'
import Header from '@/components/landing/header/Header'
import Hero from '@/components/landing/hero/Hero'
import { authOptions } from '@/utils/authOptions'
import { getServerSession, Session } from 'next-auth'

export const metadata: Metadata = {
title: '로레디 - 로스트아크 레이드 일정 관리, 공대 편성',
description: '디스코드 로레디봇을 통해 만든 레이드를 구성하고 관리할 수 있는 사이트'
}

export default function Home() {
export default async function Home() {
const session = (await getServerSession(authOptions)) as Session

return (
<div className='w-full p-7 space-y-4 h-dvh flex flex-col bg-light dark:bg-dark dark:text-light max-sm:p-5'>
<Header />
<Header session={session} />
<Hero />
</div>
)
Expand Down
14 changes: 14 additions & 0 deletions src/components/landing/header/Contact.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { FaDiscord } from 'react-icons/fa'

export default function Contact() {
return (
<a
href={process.env.NEXT_PUBLIC_DISCORD_CHANNEL}
target='_blank'
rel='noopener noreferrer'
className='flex items-center justify-center w-[35px] h-[35px] bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500 p-1 rounded-full hover:scale-125 transition'
>
<FaDiscord color='white' size={20} />
</a>
)
}
40 changes: 27 additions & 13 deletions src/components/landing/header/Gnb.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,44 @@
'use client'

import { getUserData } from '@/api/firebase'
import { User } from '@/types/users'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/utils/authOptions'
import { Session } from 'next-auth'
import HeaderLink from './HeaderLink'
import { useEffect, useState } from 'react'

interface Ownprops {
session: Session
}

export default async function Gnb() {
let dashboardUrl = ''
const session = await getServerSession(authOptions)
export default function Gnb({ session }: Ownprops) {
const [dashboardUrl, setDashboardUrl] = useState<string>('')

if (session) {
const { channels } = (await getUserData(session.user.id)) as User
dashboardUrl = `${channels[0]}/dashboard`
}
useEffect(() => {
const fetchChannel = async () => {
if (session) {
const { channels } = (await getUserData(session.user.id)) as User
setDashboardUrl(`/${channels[0]}/dashboard`)
}
}

fetchChannel()
}, [])

return (
<ul className='gap-4 hidden sm:flex'>
<li>
<ul className='gap-4 sm:flex hidden'>
<li className='lg:flex hidden'>
<HeaderLink href={process.env.NEXT_PUBLIC_DOCUMENT_LINK as string} target='_blank'>
사용법
</HeaderLink>
</li>
<li>
<li className='lg:flex hidden'>
<HeaderLink href={process.env.NEXT_PUBLIC_ADDBOT_LINK as string}>봇 추가하기</HeaderLink>
</li>
<li className='flex'>
<HeaderLink href='/characters'>유저 검색</HeaderLink>
</li>
{session && (
<li>
<li className='flex'>
<HeaderLink href={dashboardUrl}>대시보드</HeaderLink>
</li>
)}
Expand Down
37 changes: 37 additions & 0 deletions src/components/landing/header/GnbMobile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use client'

import { getUserData } from '@/api/firebase'
import { User } from '@/types/users'
import { Session } from 'next-auth'
import HeaderLink from './HeaderLink'
import { useEffect, useState } from 'react'

interface Ownprops {
session: Session
}

export default function GnbMobile({ session }: Ownprops) {
const [dashboardUrl, setDashboardUrl] = useState<string>('')

useEffect(() => {
const fetchChannel = async () => {
if (session) {
const { channels } = (await getUserData(session.user.id)) as User
setDashboardUrl(`/${channels[0]}/dashboard`)
}
}

fetchChannel()
}, [])

return (
<ul className='gap-4 flex flex-col'>
<HeaderLink href={process.env.NEXT_PUBLIC_DOCUMENT_LINK as string} target='_blank'>
사용법
</HeaderLink>
<HeaderLink href={process.env.NEXT_PUBLIC_ADDBOT_LINK as string}>봇 추가하기</HeaderLink>
<HeaderLink href='/characters'>유저 검색</HeaderLink>
{session && <HeaderLink href={dashboardUrl}>대시보드</HeaderLink>}
</ul>
)
}
53 changes: 47 additions & 6 deletions src/components/landing/header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,64 @@
'use client'

import { useState } from 'react'
import Link from 'next/link'
import Image from 'next/image'
import ThemeButton from '@/components/layout/sidebar/ThemeButton'
import AuthButton from '@/components/auth/AuthButton'
import Gnb from './Gnb'
import { FaBars, FaTimes } from 'react-icons/fa'
import { Session } from 'next-auth'
import GnbMobile from './GnbMobile'
import Contact from './Contact'

interface Ownprops {
session: Session
}

export default function Header({ session }: Ownprops) {
const [isMenuOpen, setIsMenuOpen] = useState(false)

const toggleMenu = () => {
setIsMenuOpen(!isMenuOpen)
}

export default function Header() {
return (
<header className='flex justify-between w-full'>
<nav className='flex space-x-4 items-center'>
<header className='flex justify-between w-full relative'>
<nav className='flex space-x-4 items-center '>
<Link className='w-28 pt-0.5' href='/'>
<Image className='w-full h-full' src='/images/logo.svg' alt='로레디 로고' width={100} height={50} priority />
</Link>
<div className='shrink-0 h-full w-[1px] border-l dark:border-primary-gray/50 hidden sm:flex'></div>
<Gnb />
<div className='shrink-0 h-full w-[1px] border-l dark:border-primary-gray/50 flex '></div>
<div className='hidden sm:block'>
<Gnb session={session} />
</div>
</nav>
<div className='flex items-center gap-4 max-sm:gap-3'>

<div className='hidden items-center gap-4 max-sm:gap-3 sm:flex'>
<ThemeButton />
<AuthButton />
</div>

<button className='sm:hidden flex justify-center items-center' onClick={toggleMenu}>
{isMenuOpen ? (
<FaTimes className='text-2xl rounded transition hover:rotate-90 text-dark dark:text-light' />
) : (
<FaBars className='text-2xl rounded transition hover:rotate-90 text-dark dark:text-light' />
)}
</button>

{isMenuOpen && (
<div className='absolute top-full right-0 shadow-md z-50 bg-white dark:bg-dark sm:hidden rounded-lg'>
<div className='flex flex-col p-4 space-y-4'>
<AuthButton />
<GnbMobile session={session} />
<div className='flex gap-4 items-center'>
<ThemeButton />
<Contact />
</div>
</div>
</div>
)}
</header>
)
}
2 changes: 1 addition & 1 deletion src/components/landing/header/HeaderLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface Ownprops {
export default function HeaderLink({ href, children, isDisabled = false, target = '_self' }: Ownprops) {
return (
<Link
className={`transition hover:bg-secondary-gray/50 rounded px-2 ${
className={`transition hover:bg-secondary-gray hover:dark:bg-secondary-gray/20 rounded p-2 ${
isDisabled ? 'pointer-events-none opacity-50' : ''
}`}
href={href}
Expand Down
4 changes: 1 addition & 3 deletions src/components/layout/sidebar/SideBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import Link from 'next/link'
import { FaDiscord } from 'react-icons/fa'

export default function SideBar() {
const contactDiscordURL = 'https://discord.gg/JR26Kcr3'

return (
<aside className='w-72 2xl:flex 2xl:flex-col hidden bg-white border-r border-secondary-gray/50 dark:bg-neutral-900 dark:border-primary-gray/50'>
<header className='flex items-center p-7'>
Expand Down Expand Up @@ -45,7 +43,7 @@ export default function SideBar() {
This site is not associated with Smilegae RPG. &copy; 2024. LoReady. All rights reserved.
</div>
<a
href={contactDiscordURL}
href={process.env.NEXT_PUBLIC_DISCORD_CHANNEL}
target='_blank'
rel='noopener noreferrer'
className='bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500 p-1 rounded-full hover:scale-125 transition'
Expand Down
6 changes: 3 additions & 3 deletions src/components/members/MemberCard.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { getCharacterProfile } from '@/api/lostark/getCharacterProfile'
import { ChaListInterface } from '@/types/characterList'
import { User } from '@/types/users'
import { Session } from 'next-auth'
import Image from 'next/image'
import Setting from './Setting'
import { FaExclamationCircle } from 'react-icons/fa'
import { ArmoryProfileInterface } from '@/types/Equipments/armory'

interface OwnProps {
members: User[]
Expand All @@ -27,7 +27,7 @@ const CharacterInfo = ({ label, value }: { label: string; value: string | number
</div>
)

const MemberCardContent = ({ data, m, session }: { data: ChaListInterface; m: User; session: Session }) => (
const MemberCardContent = ({ data, m, session }: { data: ArmoryProfileInterface; m: User; session: Session }) => (
<>
<header className='flex flex-col justify-center border-b space-y-4'>
<div className='flex'>
Expand Down Expand Up @@ -87,7 +87,7 @@ const MemberCard = async ({ members, session }: OwnProps) => {
<ul className='flex gap-4 w-full h-full flex-wrap justify-center sm:justify-normal overflow-y-auto'>
{await Promise.all(
sortedMembers.map(async m => {
const data = (await getCharacterProfile(m.registeredBy)) as ChaListInterface
const data = (await getCharacterProfile(m.registeredBy)) as ArmoryProfileInterface

const isCurrentUser = session.user.name === m.username
const cardClassName = `rounded flex flex-col p-4 w-[16.5rem] h-[20rem] justify-between ${
Expand Down
8 changes: 4 additions & 4 deletions src/components/members/SettingModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { updateRegisteredChar } from '@/api/firebase'
import { getCharacterList } from '@/api/lostark/getCharacterList'
import { ChaListInterface } from '@/types/characterList'
import { ArmoryProfileInterface } from '@/types/Equipments/armory'
import { Session } from 'next-auth'
import { useReducer, useEffect, useCallback, useMemo } from 'react'
import { FaCheck, FaSort } from 'react-icons/fa'
Expand All @@ -14,14 +14,14 @@ interface OwnProps {
interface State {
selected: string
isDropdownOpen: boolean
charList: ChaListInterface[]
charList: ArmoryProfileInterface[]
error: string | null
}

type Action =
| { type: 'SET_SELECTED'; payload: string }
| { type: 'TOGGLE_DROPDOWN' }
| { type: 'SET_CHAR_LIST'; payload: ChaListInterface[] }
| { type: 'SET_CHAR_LIST'; payload: ArmoryProfileInterface[] }
| { type: 'SET_ERROR'; payload: string }

const initialState: State = {
Expand Down Expand Up @@ -135,7 +135,7 @@ export default function SettingModal({ setIsOpen, registeredBy, session }: OwnPr
}

interface CharacterItemProps {
character: ChaListInterface
character: ArmoryProfileInterface
isSelected: boolean
onClick: () => void
}
Expand Down
Loading