Skip to content
6 changes: 3 additions & 3 deletions apis/MyAccessListApi.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import axios from './AxiosInstance';

// 출입증 목록 조회
export const getAccessList = () => {
const response = axios.get('/passes');
export const getAccessList = async () => {
const response = await axios.get('/passes');

return response;
return response.data.data;
};
2 changes: 1 addition & 1 deletion app.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default {
},
extra: {
//BASE_URL: 'http://keywe.site', // EKS 사용시
BASE_URL: 'http://192.168.0.225:8081', // 도커 사용시 - 본인 pc IPv4 주소로 수정하세용
BASE_URL: 'http://192.168.0.111:8081', // 도커 사용시 - 본인 pc IPv4 주소로 수정하세용
},
},
};
Binary file modified assets/images/logoGreen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/images/logoIcon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/logoLoading.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/images/logoText.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/images/logoWhite.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion components/cards/Dot.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const Dot = ({ active }) => {
useEffect(() => {
Animated.timing(animatedWidth, {
toValue: active ? DOT_ACTIVE_WIDTH : DOT_WIDTH,
duration: 300,
duration: 200,
useNativeDriver: false,
}).start();
}, [active, animatedWidth]);
Expand Down
81 changes: 81 additions & 0 deletions components/cards/DotPagination.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { useMemo, useEffect, useRef } from 'react';
import { View, TouchableOpacity, Text, Animated } from 'react-native';
import Dot from './Dot';
import { styles } from './styles/DotPagination.styles';

// 한번에 보이는 최대 DOT 개수
const MAX_DOTS = 8;

const DotPagination = ({ total, currentIndex, onPress }) => {
const groupCount = Math.ceil(total / MAX_DOTS); //전체 도트 수를 MAX_DOTS로 나눈 그룹 개수
const currentGroup = Math.floor(currentIndex / MAX_DOTS); //현재 인덱스가 속한 그룹 번호
const start = currentGroup * MAX_DOTS; // 현재 그룹에서 첫번째 도트 인덱스
const end = Math.min(start + MAX_DOTS, total); // 현재 그룹에서 마지막 도트 다음 인덱스
// 현재 그룹에서 보여줄 도트 인덱스
// useMemo를 통해 최적화(start, end가 변하지 않으면 이전에 만든 배열을 재사용)
const dotIndexes = useMemo(
() => Array.from({ length: end - start }, (_, i) => start + i), // 각 요소의 인덱스 i에 start를 더함
[start, end],
);

// 왼쪽/오른쪽 화살표의 애니메이션 위치값 (초기값: 첫그룹이면 왼쪽은 숨김, 마지막그룹이면 오른쪽은 숨김)
const leftArrowTranslate = useRef(new Animated.Value(currentGroup > 0 ? 0 : -30)).current;
const rightArrowTranslate = useRef(
new Animated.Value(currentGroup < groupCount - 1 ? 0 : 30),
).current;

// 그룹이 바뀔 때마다 왼쪽 화살표 애니메이션
useEffect(() => {
Animated.timing(leftArrowTranslate, {
toValue: currentGroup > 0 ? 0 : -30, // 첫그룹이면 숨김(-30), 아니면 보임(0)
duration: 250,
useNativeDriver: true,
}).start();
}, [currentGroup, leftArrowTranslate]);

// 그룹이 바뀔 때마다 오른쪽 화살표 애니메이션
useEffect(() => {
Animated.timing(rightArrowTranslate, {
toValue: currentGroup < groupCount - 1 ? 0 : 30, // 마지막그룹이면 숨김(30), 아니면 보임(0)
duration: 250,
useNativeDriver: true,
}).start();
}, [currentGroup, rightArrowTranslate, groupCount]);

// 왼쪽 화살표 클릭: 첫 그룹으로 이동
const goToFirstGroup = () => onPress(0);
// 오른쪽 화살표 클릭: 마지막 그룹의 첫 도트로 이동
const goToLastGroup = () => onPress((groupCount - 1) * MAX_DOTS);

return (
<View style={styles.container}>
<View style={styles.arrowContainer}>
<Animated.View style={{ transform: [{ translateX: leftArrowTranslate }] }}>
{currentGroup > 0 && (
<TouchableOpacity onPress={goToFirstGroup} style={styles.arrow}>
<Text style={styles.arrowText}>{'<'}</Text>
</TouchableOpacity>
)}
</Animated.View>
</View>
<View style={styles.dotsWrapper}>
{dotIndexes.map((idx) => (
<TouchableOpacity key={idx} onPress={() => onPress(idx)}>
<Dot active={currentIndex === idx} />
</TouchableOpacity>
))}
</View>
<View style={styles.arrowContainer}>
<Animated.View style={{ transform: [{ translateX: rightArrowTranslate }] }}>
{currentGroup < groupCount - 1 && (
<TouchableOpacity onPress={goToLastGroup} style={styles.arrow}>
<Text style={styles.arrowText}>{'>'}</Text>
</TouchableOpacity>
)}
</Animated.View>
</View>
</View>
);
};

export default DotPagination;
6 changes: 4 additions & 2 deletions components/cards/QrCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import { colors } from '../../constants/colors';
import { hospitalName } from '../../mocks/hospitalData';

// hasAccessAuthority: 출입 권한 여부, userVC : VC에 담을 사용자 정보, qrData : QR에 담을 JSON 문자열
const QrCard = ({ hasAccessAuthority, did, userName, hospitalName }) => {
const QrCard = ({ hasAccessAuthority, did, userName, hospitalName, startDate, expireDate }) => {
// 해당 QR의 상세 페이지로 이동 (아직 미구현)
//const navigation = useNavigation();
// const navigateToAccessListDeatail = () => {
// navigation.navigate('AccessListDetailPage');
// };

// 임시: QR에 담을 JSON 문자열
const qrData = JSON.stringify({ did, userName, hospitalName });
const qrData = JSON.stringify({ did, userName, hospitalName, startDate, expireDate });
return (
<View style={styles.shadowWrapper}>
<View style={styles.cardContainer}>
Expand All @@ -32,6 +32,8 @@ const QrCard = ({ hasAccessAuthority, did, userName, hospitalName }) => {
<QRCode value={qrData} size={140} color={colors.black} backgroundColor={colors.white} />
<Text style={styles.userName}>{userName}</Text>
<Text style={styles.hospital}>{hospitalName}</Text>
<Text style={styles.hospital}>시작일: {startDate}</Text>
<Text style={styles.hospital}>만료일: {expireDate}</Text>
</>
) : (
<>
Expand Down
22 changes: 11 additions & 11 deletions components/cards/QrCards.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ import React, { useRef, useState } from 'react';
import { FlatList, View, Dimensions, TouchableOpacity } from 'react-native';
import QrCard from './QrCard';
import styles from './styles/QrCards.styles';
import Dot from './Dot';
import DotPagination from './DotPagination';

// 화면의 가로 길이 가져오기
const { width } = Dimensions.get('window');
const CARD_WIDTH = width;
const SIDE_PADDING = (width - CARD_WIDTH) / 2; // 좌우 패딩 계산
const OVERLAP = 80; // 카드가 겹치는 정도

const QrCards = ({ userVC, hasAccessAuthority }) => {
Expand All @@ -32,7 +31,8 @@ const QrCards = ({ userVC, hasAccessAuthority }) => {

// dot(인디케이터) 클릭 시 해당 카드로 이동
const handleDotPress = (index) => {
flatListRef.current?.scrollToIndex({ index, animated: true });
const offset = index * (CARD_WIDTH - OVERLAP);
flatListRef.current?.scrollToOffset({ offset, animated: true });
};

// 카드 리스트
Expand All @@ -47,9 +47,11 @@ const QrCards = ({ userVC, hasAccessAuthority }) => {
pagingEnabled={false} // snapToInterval을 사용하므로 false
snapToInterval={CARD_WIDTH - OVERLAP} // 카드 단위로 스냅
decelerationRate="fast" // 빠른 스냅 효과
contentContainerStyle={{
paddingHorizontal: SIDE_PADDING, // 양쪽에 패딩 추가로 옆 카드 살짝 보이게
}}
getItemLayout={(data, index) => ({
length: CARD_WIDTH - OVERLAP,
offset: (CARD_WIDTH - OVERLAP) * index,
index,
})}
renderItem={({ item, index }) => (
<View
style={{
Expand All @@ -63,18 +65,16 @@ const QrCards = ({ userVC, hasAccessAuthority }) => {
did={item.did}
userName={item.userName}
hospitalName={item.hospitalName}
startDate={item.startDate}
expireDate={item.expireDate}
hasAccessAuthority={true}
/>
</View>
)}
onMomentumScrollEnd={onMomentumScrollEnd}
/>
<View style={styles.dotContainer}>
{userVC.map((_, i) => (
<TouchableOpacity key={`dot-${i}`} onPress={() => handleDotPress(i)}>
<Dot active={pageIndex === i} />
</TouchableOpacity>
))}
<DotPagination total={userVC.length} currentIndex={pageIndex} onPress={handleDotPress} />
</View>
</View>
);
Expand Down
37 changes: 37 additions & 0 deletions components/cards/styles/DotPagination.styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { StyleSheet } from 'react-native';
import { colors } from '../../../constants/colors';
// TODO: 도트 상수 문서화 필요할지도.. 통일
export const DOT_SIZE = 12; // 도트 크기
export const DOT_MARGIN = 8; // 도트 사이 간격
export const MAX_DOTS = 8; // 한 그룹 최대 도트 수

export const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
alignSelf: 'center',
marginVertical: 16,
},
arrowContainer: {
width: 40,
alignItems: 'center',
justifyContent: 'center',
},
arrow: {
paddingHorizontal: 8,
justifyContent: 'center',
alignItems: 'center',
},
arrowText: {
fontSize: 24,
fontWeight: 'bold',
color: colors.darkGray,
},
dotsWrapper: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
flex: 0,
minWidth: DOT_SIZE * MAX_DOTS + DOT_MARGIN * (MAX_DOTS - 1),
},
});
2 changes: 1 addition & 1 deletion components/cards/styles/QrCard.styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const styles = StyleSheet.create({
elevation: 7, // Android용
borderRadius: 15,
width: '70%',
height: '80%',
height: '85%', //TODO : 기존에는 80이었는데, 추후 카드 높이 변경 필요할듯함
marginVertical: '10%',
},
cardContainer: {
Expand Down
4 changes: 2 additions & 2 deletions components/lists/NormalListDeep.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import { styles } from './styles/NormalListDeep.styles'; //노말리스트와

// TODO: Pass-Service 구현 완료 시, 실제 데이터로 변경 필요
//리스트안에 노말리스트가 있는 컴포넌트
const NormalListDeep = ({ sections = [], onItemPress, renderItem }) => {
const NormalListDeep = ({ sections = [], onItemPress, renderItem, cardStyle }) => {
return (
<ScrollView style={styles.scrollView} contentContainerStyle={styles.contentContainer}>
{sections.map((section, idx) => (
//console.log('Section', section),
<View key={section.contentTitle || idx} style={styles.itemBox}>
<Text style={styles.itemText}>{section.contentTitle}</Text>
<NormalList
items={section.accessList}
renderItem={renderItem}
style={cardStyle}
//아이템 클릭 시 section 정보 함께 상위로 전달
onItemPress={(item, index) => {
if (onItemPress) onItemPress(section, item, index);
Expand Down
1 change: 0 additions & 1 deletion components/lists/styles/NormalListDeep.styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export const styles = StyleSheet.create({
contentContainer: { paddingBottom: 60 },
// 각 아이템 박스 스타일
itemBox: {
marginBottom: 10,
marginBottom: -40,
},
// 각 아이템 텍스트 스타일
Expand Down
2 changes: 1 addition & 1 deletion components/loadings/KiwiSpinner.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const KiwiSpinner = () => {
return (
<View style={styles.contentContainer}>
<Animated.Image //이미지를 애니메이션 처리
source={require('../../assets/images/logoIcon.png')}
source={require('../../assets/images/logoLoading.png')}
style={[styles.animationImage, { transform: [{ rotate: spin }] }]}
resizeMode="contain"
/>
Expand Down
2 changes: 2 additions & 0 deletions constants/colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export const colors = {
background: '#F0F0F0',
white: '#FFFFFF',
black: '#464646',
moreLightGreen: '#E7EDE8',
moreLightGray: '#DFDFDF',
lightGray: '#B7B7B7',
darkGray: '#7E7E7E',
primary: '#24562B', // 메인 포인트 색상
Expand Down
5 changes: 3 additions & 2 deletions modals/MyAccessDetailModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ const MyAccessDetailModal = ({ isVisible, onClose, onConfirm, data }) => {
<Text style={styles.modalContentTitle}>{data.area}</Text>
<View style={styles.textContainer}>
<Text style={styles.modalText}>방문자: {data.visitorType}</Text>
<Text style={styles.modalText}>시작일: {data.startDate}</Text>
<Text style={styles.modalText}>만료일: {data.expireDate}</Text>
<Text style={styles.modalText}>승인 여부: {data.approval}</Text>
<Text style={styles.modalText}>환자 번호: {data.patientNumber}</Text>
</View>
<Text style={styles.modalContentTitle}>내 보호자</Text>
<View style={styles.textContainer}>
<Text style={styles.modalText}>{`김OO\t|\t010-0000-0000`}</Text>
<Text style={styles.modalText}>{`김OO\t|\t010-0000-0000`}</Text>
<Text style={styles.modalText}>{`김지수\t|\t010-0000-0000`}</Text>
<Text style={styles.modalText}>{`손민지\t|\t010-1111-1111`}</Text>
</View>

<View style={styles.buttonRow}>
Expand Down
8 changes: 4 additions & 4 deletions modals/styles/MyAccessDetailModal.styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ export const styles = StyleSheet.create({
alignSelf: 'center',
},
modalTitle: {
fontSize: 25,
fontSize: 22,
fontWeight: '600',
color: colors.black,
marginTop: '7%',
alignSelf: 'center',
},
modalContentTitle: {
fontSize: 20,
fontSize: 17,
fontWeight: '500',
color: colors.black,
marginTop: '5%',
Expand All @@ -31,10 +31,10 @@ export const styles = StyleSheet.create({
marginBottom: '7%',
},
modalText: {
fontSize: 18,
fontSize: 17,
fontWeight: '500',
color: colors.darkGray,
marginTop: 10,
marginTop: 2,
lineHeight: 30,
},
buttonRow: {
Expand Down
Loading