-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FEAT] #38 신규 쓰레기통 상세 뷰 (이미지 업로드 제외) 구현
- Loading branch information
Showing
7 changed files
with
279 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,14 @@ | ||
import { createNativeStackNavigator } from "@react-navigation/native-stack"; | ||
import ReportNewBin from "screens/reportNewBin/ReportNewBin"; | ||
import ReportNewBinDetail from "screens/reportNewBinDetail/ReportNewBinDetail"; | ||
|
||
export default function ReportNewBinNavigator() { | ||
const Stack = createNativeStackNavigator<RootReportNewBinParamList>(); | ||
|
||
return ( | ||
<Stack.Navigator initialRouteName="ReportNewBin" screenOptions={{headerShown: false}}> | ||
<Stack.Screen name="ReportNewBin" component={ReportNewBin} /> | ||
<Stack.Screen name="ReportNewBinDetail" component={ReportNewBinDetail} /> | ||
</Stack.Navigator> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
133 changes: 133 additions & 0 deletions
133
app/src/screens/reportNewBinDetail/ReportNewBinDetail.style.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import DefaultText from 'components/DefaultText'; | ||
import {Palette} from 'constants/palette'; | ||
import {Typo} from 'constants/typo'; | ||
import {Dimensions} from 'react-native'; | ||
import styled from 'styled-components/native'; | ||
|
||
const screenWidth = Dimensions.get('window').width; | ||
const width = screenWidth - 32; | ||
|
||
export const Container = styled.View` | ||
flex: 1; | ||
background: ${Palette.White}; | ||
padding: 10px 16px 0px; | ||
`; | ||
|
||
export const ArrowPrevWrapper = styled.TouchableOpacity` | ||
width: 24px; | ||
height: 24px; | ||
justify-content: center; | ||
align-items: center; | ||
margin-bottom: 16px; | ||
`; | ||
|
||
export const LocationWrapper = styled.View` | ||
flex-direction: row; | ||
align-items: center; | ||
gap: 3px; | ||
padding: 10px 12px; | ||
background: ${Palette.Gray1}; | ||
border-radius: 10px; | ||
shadow-color: rgba(0, 0, 0, 0.2); | ||
shadow-offset: 0px 2px; | ||
shadow-opacity: 1; | ||
shadow-radius: 6px; | ||
elevation: 3; | ||
`; | ||
|
||
export const LocationText = styled(DefaultText)` | ||
font-size: ${Typo.B3.fontSize}; | ||
font-weight: ${Typo.B3.fontWeight}; | ||
color: #3b3f4a; | ||
flex-shrink: 1; | ||
flex-wrap: wrap; | ||
`; | ||
|
||
export const Title = styled(DefaultText)` | ||
font-size: ${Typo.Title1.fontSize}; | ||
font-weight: ${Typo.Title1.fontWeight}; | ||
color: ${Palette.Black}; | ||
margin-top: 22px; | ||
margin-bottom: 26px; | ||
`; | ||
|
||
export const SubTitle = styled(DefaultText)` | ||
font-size: ${Typo.SubTitle.fontSize}; | ||
font-weight: ${Typo.SubTitle.fontWeight}; | ||
color: ${Palette.Black}; | ||
margin-bottom: 12px; | ||
`; | ||
|
||
export const SelectWrapper = styled.View` | ||
flex-direction: row; | ||
row-gap: 12px; | ||
column-gap: 16px; | ||
flex-wrap: wrap; | ||
`; | ||
|
||
export const SelectItem = styled.TouchableOpacity<{isSelected: boolean}>` | ||
padding: 10px 22px; | ||
border-radius: 22px; | ||
flex-shrink: 0; | ||
background: ${props => props.isSelected ? Palette.Primary : Palette.Gray2}; | ||
`; | ||
|
||
export const TextSelectItem = styled(DefaultText)<{isSelected: boolean}>` | ||
font-size: ${Typo.B3.fontSize}; | ||
font-weight: ${Typo.B3.fontWeight}; | ||
color: ${props => props.isSelected ? Palette.White : Palette.Gray4}; | ||
text-align: center; | ||
` | ||
|
||
export const ReviewInput = styled.TextInput` | ||
width: 100%; | ||
height: 150px; | ||
border-radius: 8px; | ||
padding: 12px 14px; | ||
background: ${Palette.Gray1}; | ||
font-size: ${Typo.B3.fontSize}; | ||
font-weight: ${Typo.B3.fontWeight}; | ||
line-height: 19px; | ||
color: ${Palette.Black}; | ||
margin: 18px 0px 15px; | ||
`; | ||
|
||
export const AddPicture = styled.TouchableOpacity` | ||
width: 100%; | ||
height: 134px; | ||
justify-content: center; | ||
background: ${Palette.P100}; | ||
border-radius: 8px; | ||
padding: 22px 15px; | ||
`; | ||
|
||
export const IconAddPicture = styled.ImageBackground` | ||
width: 35px; | ||
height: 35px; | ||
align-self: center; | ||
margin-bottom: 10px; | ||
` | ||
|
||
export const TextB3 = styled(DefaultText)` | ||
font-size: ${Typo.B3.fontSize}; | ||
font-weight: ${Typo.B3.fontWeight}; | ||
color: ${Palette.Gray6}; | ||
text-align: center; | ||
`; | ||
|
||
export const Button = styled.TouchableOpacity<{isValid: boolean}>` | ||
width: 100%; | ||
padding: 16px 30px; | ||
justify-content: center; | ||
align-items: center; | ||
background: ${props => props.isValid ? Palette.Primary : Palette.Gray3}; | ||
border-radius: 10px; | ||
margin-bottom: 20px; | ||
`; | ||
|
||
export const ButtonText = styled(DefaultText)<{isValid: boolean}>` | ||
font-size: ${Typo.Button1.fontSize}; | ||
font-weight: ${Typo.Button1.fontWeight}; | ||
color: ${props => props.isValid ? Palette.White : Palette.Gray5}; | ||
`; |
122 changes: 122 additions & 0 deletions
122
app/src/screens/reportNewBinDetail/ReportNewBinDetail.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import {NavigationProp, RouteProp, useNavigation} from '@react-navigation/native'; | ||
import api from 'api/api'; | ||
import CancelSvg from 'assets/images/CancelSvg'; | ||
import LocationSvg from 'assets/images/LocationSvg'; | ||
import {Palette} from 'constants/palette'; | ||
import {useEffect, useState} from 'react'; | ||
import {ScrollView} from 'react-native'; | ||
import Toast from 'react-native-toast-message'; | ||
import * as S from 'screens/reportNewBinDetail/ReportNewBinDetail.style'; | ||
|
||
type ReportNewBinProps = { | ||
route: RouteProp<RootReportNewBinParamList, 'ReportNewBinDetail'>; | ||
} | ||
|
||
export default function ReportNewBinDetail({route}: ReportNewBinProps) { | ||
const {address, coordinate} = route.params; | ||
const navigation = useNavigation<NavigationProp<RootReportNewBinParamList>>(); | ||
const navigation2 = useNavigation<NavigationProp<RootHomeParamList>>(); | ||
const binTypeLabel = ['Trash', 'Recycling']; | ||
const locationDetailLabel = ['Subway Entrance', 'Bus/Taxi Stop', 'Roadside', 'Square/Park', 'Other']; | ||
const [selectedBinTypeLabel, setSelectedBinTypeLabel] = useState<number>(-1); | ||
const [selectedLocationDetailLabel, setSelectedLocationDetailLabel] = useState<number>(-1); | ||
const placeholder = `In front of a store (e.g. Olive Young) or by the bus stop? More details will help fellow wanderers!`; | ||
const [content, setContent] = useState<string>(''); | ||
const [isValid, setIsValid] = useState<boolean>(false); | ||
|
||
const handleSubmit = async () => { | ||
try { | ||
const response = await api.post(`/bin/new`, { | ||
address: address, | ||
lat: coordinate![0], | ||
lng: coordinate![1], | ||
detail: content, | ||
type_no: selectedBinTypeLabel === 0 ? 1 : 2, | ||
location_type_no: selectedLocationDetailLabel + 1, | ||
image: 'https://test.test/123', | ||
}); | ||
if (response.data.success) { | ||
Toast.show({ | ||
type: 'success', | ||
text1: 'Thank you for letting us know!', | ||
position: 'bottom', | ||
bottomOffset: 100, | ||
visibilityTime: 2000, | ||
}); | ||
navigation2.navigate('Home'); | ||
} else { | ||
Toast.show({ | ||
type: 'error', | ||
text1: 'Failed to submit. Please try again later.', | ||
position: 'bottom', | ||
bottomOffset: 100, | ||
visibilityTime: 2000, | ||
}); | ||
} | ||
} catch (error: any) { | ||
console.log(error); | ||
Toast.show({ | ||
type: 'error', | ||
text1: 'Failed to submit. Please try again later.', | ||
position: 'bottom', | ||
bottomOffset: 100, | ||
visibilityTime: 2000, | ||
}); | ||
} | ||
} | ||
|
||
useEffect(() => { | ||
if (selectedBinTypeLabel !== -1 && selectedLocationDetailLabel !== -1) { | ||
setIsValid(true); | ||
return; | ||
} | ||
setIsValid(false); | ||
}, [selectedBinTypeLabel, selectedLocationDetailLabel]) | ||
|
||
return ( | ||
<S.Container> | ||
<S.ArrowPrevWrapper onPress={() => navigation.goBack()}> | ||
<CancelSvg width="24" height="24" fill={Palette.Gray4} /> | ||
</S.ArrowPrevWrapper> | ||
<ScrollView bounces={false} showsVerticalScrollIndicator={false} style={{marginBottom: 30}}> | ||
<S.LocationWrapper> | ||
<LocationSvg width="24" height="24" fill={Palette.Primary} /> | ||
<S.LocationText>{address}</S.LocationText> | ||
</S.LocationWrapper> | ||
<S.Title>{`Tell us more about the bin\nyou found`}</S.Title> | ||
<S.SubTitle>Bin type</S.SubTitle> | ||
<S.SelectWrapper style={{marginBottom: 24}}> | ||
{binTypeLabel.map((item, index) => ( | ||
<S.SelectItem key={index} isSelected={selectedBinTypeLabel === index} onPress={() => setSelectedBinTypeLabel(index)}> | ||
<S.TextSelectItem isSelected={selectedBinTypeLabel === index}>{item}</S.TextSelectItem> | ||
</S.SelectItem> | ||
))} | ||
</S.SelectWrapper> | ||
<S.SubTitle>Location details</S.SubTitle> | ||
<S.SelectWrapper> | ||
{locationDetailLabel.map((item, index) => ( | ||
<S.SelectItem key={index} isSelected={selectedLocationDetailLabel === index} onPress={() => setSelectedLocationDetailLabel(index)}> | ||
<S.TextSelectItem isSelected={selectedLocationDetailLabel === index}>{item}</S.TextSelectItem> | ||
</S.SelectItem> | ||
))} | ||
</S.SelectWrapper> | ||
<S.ReviewInput | ||
value={content} | ||
onChangeText={setContent} | ||
placeholder={placeholder} | ||
placeholderTextColor={Palette.Gray4} | ||
multiline | ||
textAlignVertical="top" | ||
/> | ||
<S.AddPicture> | ||
<S.IconAddPicture source={require('assets/images/AddImage.png')} /> | ||
<S.SubTitle style={{textAlign: 'center', marginBottom: 0}}>Upload a photo of the bin (Optional)</S.SubTitle> | ||
<S.TextB3>You can upload only one photo!</S.TextB3> | ||
</S.AddPicture> | ||
</ScrollView> | ||
<S.Button disabled={!isValid} isValid={isValid} onPress={handleSubmit}> | ||
<S.ButtonText isValid={isValid}>Submit</S.ButtonText> | ||
</S.Button> | ||
</S.Container> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters