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
10 changes: 10 additions & 0 deletions src/apis/ticket/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,14 @@ export const ticketMutations = {
},
})
},

deleteTicket: () => {
return useMutation({
mutationFn: ({ ticketId }: { ticketId: number }) =>
api().deletePost(ticketId),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ticketKeys.ticketList.all() })
},
})
},
}
8 changes: 4 additions & 4 deletions src/app/(auth)/add-ticket/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ export const schema = z.object({
/**
* 관람좌석
*/
floor: z.string().min(1),
zone: z.string().min(1),
col: z.string().min(1),
seatNumber: z.string().min(1),
floor: z.string().optional(),
zone: z.string().optional(),
col: z.string().optional(),
seatNumber: z.string().optional(),

/**
* 관람 일정
Expand Down
16 changes: 9 additions & 7 deletions src/app/(auth)/add-ticket/step4/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
import { zodResolver } from '@hookform/resolvers/zod'
import * as ImagePicker from 'expo-image-picker'
import { useLocalSearchParams, useRouter } from 'expo-router'
import { overlay } from 'overlay-kit'
import { useForm } from 'react-hook-form'
import { Image } from 'react-native'
import { ticketMutations } from '@/apis/ticket/mutations'
import { BottomSheet } from '@/components/BottomSheet'
import { Button } from '@/components/Button'
Expand All @@ -17,6 +11,12 @@ import { toast } from '@/components/Toaster'
import { useUser } from '@/providers/user.provider'
import { cn } from '@/utils/cn'
import { uploadImage } from '@/utils/upload-image'
import { zodResolver } from '@hookform/resolvers/zod'
import * as ImagePicker from 'expo-image-picker'
import { useLocalSearchParams, useRouter } from 'expo-router'
import { overlay } from 'overlay-kit'
import { useForm } from 'react-hook-form'
import { Image } from 'react-native'
import AddTicketHeader from '../components/AddTicketHeader'
import { type FormType, schema } from '../schema'

Expand Down Expand Up @@ -105,7 +105,9 @@ export default function Step4() {
col: data.col,
number: data.seatNumber,
actor_ids: data.actors.map((actor) => actor.id),
ticket_image_url: `/${data.dynamicTicketImageUrl}`,
ticket_image_url: data.noTicketUpload
? undefined
: `/${data.dynamicTicketImageUrl}`,
})

toast.show('티켓을 등록했어요.')
Expand Down
107 changes: 62 additions & 45 deletions src/app/(auth)/ticket-detail/[id]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
import { zodResolver } from '@hookform/resolvers/zod'
import { useQuery, useSuspenseQuery } from '@tanstack/react-query'
import dayjs from 'dayjs'
import * as ImagePicker from 'expo-image-picker'
import { useLocalSearchParams } from 'expo-router'
import { overlay } from 'overlay-kit'
import { useEffect, useState } from 'react'
import { Controller, useForm } from 'react-hook-form'
import { Image, TextInput } from 'react-native'
import { FlatList } from 'react-native-gesture-handler'
import { imageMutations } from '@/apis/image/mutations'
import { ticketMutations } from '@/apis/ticket/mutations'
import { ticketQueries } from '@/apis/ticket/queries'
import { BottomSheet } from '@/components/BottomSheet'
import { Calendar } from '@/components/Calendar'
import { Icon } from '@/components/common/icons/Icon'
import { Col, Flex, Row } from '@/components/common/ui/Flex'
import { Screen } from '@/components/common/ui/Screen'
import { Spacing } from '@/components/common/ui/Spacing'
import { Text } from '@/components/common/ui/Text'
import { Dialog } from '@/components/Dialog'
import { Dropdown } from '@/components/Dropdown'
Expand All @@ -27,25 +17,35 @@ import { toast } from '@/components/Toaster'
import { useDebounce } from '@/hooks/useDebounce'
import { cn } from '@/utils/cn'
import { uploadImage } from '@/utils/upload-image'
import { zodResolver } from '@hookform/resolvers/zod'
import { useQuery, useSuspenseQuery } from '@tanstack/react-query'
import dayjs from 'dayjs'
import * as ImagePicker from 'expo-image-picker'
import { router, useLocalSearchParams } from 'expo-router'
import { overlay } from 'overlay-kit'
import { useRef, useState } from 'react'
import { Controller, useForm } from 'react-hook-form'
import { Image, type LayoutChangeEvent, TextInput } from 'react-native'
import { FlatList, type ScrollView } from 'react-native-gesture-handler'
import { type FormType, schema } from '../../add-ticket/schema'

export default function TicketDetailScreen() {
const { id } = useLocalSearchParams()

const scrollRef = useRef<ScrollView>(null)
const actorSectionY = useRef(0)
const { mutate: updateTicket } = ticketMutations.updateTicket()

const [actorKeyword, setActorKeyword] = useState('')

const { data } = useSuspenseQuery(ticketQueries.getTicketDetail(Number(id)))
const { mutate: deleteTicket } = ticketMutations.deleteTicket()

const { data: actors } = useQuery(
ticketQueries.searchActors({
keyword: useDebounce(actorKeyword, 150),
}),
)

const { mutate: getTicketImage } = imageMutations.getViewImage()

const form = useForm<FormType>({
resolver: zodResolver(schema),
defaultValues: {
Expand Down Expand Up @@ -73,19 +73,6 @@ export default function TicketDetailScreen() {

const [isEdit, setIsEdit] = useState(false)

useEffect(() => {
if (!data?.ticket_image_url) {
form.setValue('ticketImageUrl', undefined)
return
}
const match = data?.ticket_image_url?.match(/dynamic\/[\w-]+\.\w+/)?.[0]

getTicketImage(
{ file_path: match },
{ onSuccess: (data) => form.setValue('ticketImageUrl', data?.url ?? '') },
)
}, [data?.ticket_image_url, getTicketImage])

const onDelete = async () => {
overlay.open(({ isOpen, close }) => (
<Dialog
Expand All @@ -95,6 +82,20 @@ export default function TicketDetailScreen() {
description="삭제한 내역은 되돌릴 수 없어요."
top="확인"
bottom="취소"
onTopPress={() => {
close()
deleteTicket(
{
ticketId: Number(id),
},
{
onSuccess: () => {
toast.show('관람 내역을 삭제했어요.')
router.back()
},
},
)
}}
/>
))
}
Expand All @@ -118,9 +119,9 @@ export default function TicketDetailScreen() {
onTicketImageUpload()
}}
>
<Icon name="Image" size={24} />
<Icon name="Image" size={24} className="text-black" />
<Text variant="subhead-03" color="gray-09">
갤러리에서 사진 변경하기
갤러리에서 변경하기
</Text>
</Row>
{type === 'EDIT' && (
Expand All @@ -132,7 +133,7 @@ export default function TicketDetailScreen() {
onClose()
}}
>
<Icon name="Delete" size={24} color="sub-alert" />
<Icon name="Delete" size={24} className="text-sub-alert" />
<Text variant="subhead-03" color="sub-alert">
사진 삭제하기
</Text>
Expand Down Expand Up @@ -185,6 +186,7 @@ export default function TicketDetailScreen() {
<Screen
className="pt-[15px] pb-[170px]"
scrollable
scrollRef={scrollRef}
header={
<Header>
{isEdit ? (
Expand Down Expand Up @@ -393,10 +395,24 @@ export default function TicketDetailScreen() {
티켓 사진
</Text>
<Flex center className="relative h-[176px] rounded-lg bg-gray-10">
{isEdit ? (
{form.watch('ticketImageUrl') && (
<Image
source={{ uri: form.watch('ticketImageUrl') }}
className="absolute inset-0 z-10 size-full rounded-lg"
resizeMode="cover"
/>
)}
{!isEdit && !form.watch('ticketImageUrl') && (
<Text
variant="caption"
color="gray-07"
className="text-center"
>{`티켓 사진을 업로드하고\n후기를 작성해보세요!`}</Text>
)}
{isEdit && (
<Col
gap={4}
align="center"
center
className="absolute inset-0 z-10 bg-gray-12/40"
onPress={() => {
if (form.watch('ticketImageUrl')) {
handleTicketSheet('EDIT')
Expand All @@ -410,21 +426,15 @@ export default function TicketDetailScreen() {
{form.watch('ticketImageUrl') ? '사진 변경' : '사진 추가'}
</Text>
</Col>
) : form.watch('ticketImageUrl') ? (
<Image
source={{ uri: form.watch('ticketImageUrl') }}
className="absolute inset-0 z-10 h-full w-full rounded-lg"
resizeMode="cover"
/>
) : (
<Text
variant="caption"
color="gray-07"
>{`티켓 사진을 업로드하고\n후기를 작성해보세요!`}</Text>
)}
</Flex>
</Col>
<Col gap={12}>
<Col
gap={12}
onLayout={(event: LayoutChangeEvent) => {
actorSectionY.current = event.nativeEvent.layout.y
}}
>
<Text variant="subhead-02" color="gray-01">
배우
</Text>
Expand All @@ -436,6 +446,12 @@ export default function TicketDetailScreen() {
onDelete={() => {
setActorKeyword('')
}}
onPress={() => {
scrollRef.current?.scrollTo({
y: actorSectionY.current,
animated: true,
})
}}
placeholder="추가할 배우 검색하기"
/>
)}
Expand Down Expand Up @@ -533,6 +549,7 @@ export default function TicketDetailScreen() {
)}
</Col>
</Col>
<Spacing size={400} />
</Screen>
)
}
14 changes: 7 additions & 7 deletions src/app/login/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
import type { UserSignupReqProvider } from 'api'
import { router } from 'expo-router'
import * as WebBrowser from 'expo-web-browser'
import { Image, View } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { userQueries } from '@/apis/user/queries'
import { Col } from '@/components/common/ui/Flex'
import { Text, type TextProps } from '@/components/common/ui/Text'
Expand All @@ -11,6 +6,11 @@ import { TERMS_AND_PRIVACY } from '@/constants/login'
import { queryClient } from '@/lib/query-client'
import { saveToken } from '@/lib/storage'
import { useAuth } from '@/providers/user.provider'
import type { UserSignupReqProvider } from 'api'
import { router } from 'expo-router'
import * as WebBrowser from 'expo-web-browser'
import { Image, View } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import LoginButton from './components/LoginButton'
import LogoText from './components/LogoText'

Expand Down Expand Up @@ -53,11 +53,11 @@ export default function Index() {

if (token) {
await saveToken('accessToken', token)
await sync()
sync()
if (isInitialized === 'true') {
router.replace('/')
} else {
router.replace('/login/profile-setup')
router.push('/login/profile-setup')
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/icons/svgs/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const Checkbox = (props: SvgProps, ref: Ref<SVGSVGElement>) => (
{...props}
>
<Path
fill="currentColor"
fill="#FBFBFB"
fillRule="evenodd"
d="M5.67 0h8.67C17.73 0 20 2.38 20 5.92v8.171C20 17.62 17.73 20 14.34 20H5.67C2.28 20 0 17.62 0 14.091V5.92C0 2.38 2.28 0 5.67 0m3.76 12.99 4.75-4.75c.34-.34.34-.89 0-1.24a.88.88 0 0 0-1.24 0l-4.13 4.13-1.75-1.75a.88.88 0 0 0-1.24 0c-.34.34-.34.89 0 1.24l2.38 2.37c.17.17.39.25.61.25.23 0 .45-.08.62-.25"
clipRule="evenodd"
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/icons/svgs/Uncheckbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const Uncheckbox = (props: SvgProps, ref: Ref<SVGSVGElement>) => (
{...props}
>
<Path
fill="currentColor"
fill="#FBFBFB"
fillRule="evenodd"
d="M5.665 1.5C3.135 1.5 1.5 3.233 1.5 5.916v8.168c0 2.683 1.635 4.416 4.165 4.416h8.668c2.531 0 4.167-1.733 4.167-4.416V5.916c0-2.683-1.636-4.416-4.166-4.416zM14.333 20H5.665C2.276 20 0 17.622 0 14.084V5.916C0 2.378 2.276 0 5.665 0h8.669C17.723 0 20 2.378 20 5.916v8.168C20 17.622 17.723 20 14.333 20"
clipRule="evenodd"
Expand Down
9 changes: 4 additions & 5 deletions src/components/common/icons/svgs/XCircle.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { forwardRef, type Ref } from 'react'
import type { SvgProps } from 'react-native-svg'
import Svg, { Path } from 'react-native-svg'

import type { SvgProps } from 'react-native-svg'
import { Ref, forwardRef } from 'react'
const XCircle = (props: SvgProps, ref: Ref<SVGSVGElement>) => (
<Svg
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -13,11 +12,11 @@ const XCircle = (props: SvgProps, ref: Ref<SVGSVGElement>) => (
{...props}
>
<Path
fill="currentColor"
fill="#6F6F6F"
d="M10 18.333a8.333 8.333 0 1 0 0-16.666 8.333 8.333 0 0 0 0 16.666"
/>
<Path
stroke="white"
stroke="#FBFBFB"
strokeLinecap="round"
strokeLinejoin="round"
d="m12.5 7.5-5 5m0-5 5 5"
Expand Down
4 changes: 2 additions & 2 deletions src/components/common/icons/svgs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ export { ArrowRight } from './ArrowRight'
export { AvatarPlaceholder } from './AvatarPlaceholder'
export { Before } from './Before'
export { Camera } from './Camera'
export { Checkbox } from './Checkbox'
export { CheckCircle } from './CheckCircle'
export { Clock } from './Clock'
export { Close } from './Close'
Expand All @@ -26,8 +25,9 @@ export { Stopwatch } from './Stopwatch'
export { StrokeHeart } from './StrokeHeart'
export { Theaterseat } from './TheaterSeat'
export { Ticket } from './Ticket'
export { Uncheckbox } from './Uncheckbox'
export { User } from './User'
export { UserLinear } from './UserLinear'
export { Variant2 } from './Variant2'
export { Checkbox } from './Checkbox'
export { Uncheckbox } from './Uncheckbox'
export { XCircle } from './XCircle'
7 changes: 6 additions & 1 deletion src/components/common/ui/Screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ export function Screen({
className,
fixedButton,
scrollable,
scrollRef,
}: PropsWithStrictChildren<{
header?: React.ReactNode
bg?: ColorKeys
className?: string
fixedButton?: React.ReactNode
scrollable?: boolean
scrollRef?: React.Ref<ScrollView>
}>) {
const insets = useSafeAreaInsets()

Expand All @@ -32,7 +34,10 @@ export function Screen({
>
{header}
{scrollable ? (
<ScrollView contentContainerClassName={cn('px-5', className)}>
<ScrollView
ref={scrollRef}
contentContainerClassName={cn('px-5', className)}
>
{children}
</ScrollView>
) : (
Expand Down