From 3b4b248fce63d1b5e079405d08051927b6b419eb Mon Sep 17 00:00:00 2001
From: Jiwon Chae <63784453+jiwon0226@users.noreply.github.com>
Date: Tue, 13 May 2025 10:48:32 +0900
Subject: [PATCH 1/3] =?UTF-8?q?KW-157/feat:=20QrCard=20=EC=BB=B4=ED=8F=AC?=
=?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EB=A9=94?=
=?UTF-8?q?=EC=9D=B8=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=20=EC=A0=81?=
=?UTF-8?q?=EC=9A=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app.config.js | 2 +-
components/cards/QrCard.js | 46 ++++++++++++++++
components/cards/QrCards.js | 0
components/cards/styles/QrCard.styles.js | 65 +++++++++++++++++++++++
components/cards/styles/QrCards.styles.js | 0
pages/MainPage.js | 33 +-----------
6 files changed, 114 insertions(+), 32 deletions(-)
create mode 100644 components/cards/QrCard.js
create mode 100644 components/cards/QrCards.js
create mode 100644 components/cards/styles/QrCard.styles.js
create mode 100644 components/cards/styles/QrCards.styles.js
diff --git a/app.config.js b/app.config.js
index 37b8242..cfb5823 100644
--- a/app.config.js
+++ b/app.config.js
@@ -25,7 +25,7 @@ export default {
favicon: './assets/images/logoIcon.png',
},
extra: {
- BASE_URL: 'http://192.168.0.115:8081', // 본인 pc IPv4 주소로 수정하세용
+ BASE_URL: 'http://192.168.0.225:8081', // 본인 pc IPv4 주소로 수정하세용
},
},
};
diff --git a/components/cards/QrCard.js b/components/cards/QrCard.js
new file mode 100644
index 0000000..bea7dd1
--- /dev/null
+++ b/components/cards/QrCard.js
@@ -0,0 +1,46 @@
+import React, { useState } from 'react';
+import { View, Text, Image } from 'react-native';
+import { useNavigation } from '@react-navigation/native';
+import QRCode from 'react-native-qrcode-svg';
+
+import NormalButton from '../../components/buttons/NormalButton';
+import { styles } from './styles/QrCard.styles';
+import { colors } from '../../constants/colors';
+
+// hasAccessAuthority: 출입 권한 여부, userVC : VC에 담을 사용자 정보, qrData : QR에 담을 JSON 문자열
+const QrCard = ({ hasAccessAuthority, userVC, qrData }) => {
+ // 해당 QR의 상세 페이지로 이동 (아직 미구현)
+ //const navigation = useNavigation();
+ // const navigateToAccessListDeatail = () => {
+ // navigation.navigate('AccessListDetailPage');
+ // };
+
+ return (
+
+
+
+ {hasAccessAuthority ? (
+ <>
+ 임시 출입 QR
+
+ {userVC.userName}
+ {userVC.hospital1}
+ {userVC.hospital2}
+ {userVC.hospital3}
+ >
+ ) : (
+ <>
+ 등록된 출입 권한이 존재하지 않습니다.
+ 방문 신청 버튼을 눌러 출입 권한을 신청해주세요.
+ >
+ )}
+
+
+ );
+};
+
+export default QrCard;
diff --git a/components/cards/QrCards.js b/components/cards/QrCards.js
new file mode 100644
index 0000000..e69de29
diff --git a/components/cards/styles/QrCard.styles.js b/components/cards/styles/QrCard.styles.js
new file mode 100644
index 0000000..87200cb
--- /dev/null
+++ b/components/cards/styles/QrCard.styles.js
@@ -0,0 +1,65 @@
+import { StyleSheet } from 'react-native';
+import { colors } from '../../../constants/colors';
+
+export const styles = StyleSheet.create({
+ shadowWrapper: {
+ // 그림자 설정
+ shadowColor: 'black',
+ shadowOffset: { width: 0, height: 2 },
+ shadowOpacity: 0.2,
+ shadowRadius: 5,
+ elevation: 7, // Android용
+ borderRadius: 15,
+ width: '100%',
+ height: '55%',
+ marginVertical: '10%',
+ },
+ cardContainer: {
+ flex: 1, // 부모(shadowWrapper)의 크기를 꽉 채워 카드와 그림자 모양을 일치시킴
+ backgroundColor: colors.white,
+ borderRadius: 15,
+ padding: '10%',
+ alignItems: 'center',
+ justifyContent: 'center',
+ overflow: 'hidden', // 배경 이미지가 카드 안에 잘리게
+ position: 'relative', // 자식의 absolute 포지션 기준점
+ },
+ backgroundImage: {
+ ...StyleSheet.absoluteFillObject, // 전체 카드 덮게 만듦
+ width: '125%',
+ zIndex: 0, // 맨 뒤로
+ opacity: 0.5,
+ },
+ cardText: {
+ fontSize: 20,
+ fontWeight: 600,
+ color: colors.black,
+ textAlign: 'center',
+ marginBottom: '5%',
+ },
+ cardSubText: {
+ fontSize: 16,
+ fontWeight: 500,
+ color: colors.darkGray,
+ textAlign: 'center',
+ },
+ qrTitle: {
+ fontSize: 26,
+ fontWeight: 700,
+ color: colors.black,
+ marginBottom: '10%',
+ zIndex: 1, // QR과 텍스트를 배경 위에
+ },
+ userName: {
+ fontSize: 24,
+ fontWeight: 600,
+ color: colors.black,
+ marginVertical: '8%',
+ },
+ hospital: {
+ fontSize: 16,
+ fontWeight: 500,
+ color: colors.darkGray,
+ marginTop: '2%',
+ },
+});
diff --git a/components/cards/styles/QrCards.styles.js b/components/cards/styles/QrCards.styles.js
new file mode 100644
index 0000000..e69de29
diff --git a/pages/MainPage.js b/pages/MainPage.js
index bcc2fbb..85d66de 100644
--- a/pages/MainPage.js
+++ b/pages/MainPage.js
@@ -5,6 +5,7 @@ import NormalButton from '../components/buttons/NormalButton';
import { styles } from './styles/MainPage.styles';
import QRCode from 'react-native-qrcode-svg';
import { colors } from '../constants/colors';
+import QrCard from '../components/cards/QrCard';
const MainPage = () => {
// 임시: 상태변수로 출입 권한 제어
@@ -39,37 +40,7 @@ const MainPage = () => {
source={require('../assets/images/logoGreen.png')}
resizeMode="contain" // 이미지 비율 유지
/>
-
-
-
- {hasAccessAuthority ? (
- <>
- 임시 출입 QR
-
- {userVC.userName}
- {userVC.hospital1}
- {userVC.hospital2}
- {userVC.hospital3}
- >
- ) : (
- <>
- 등록된 출입 권한이 존재하지 않습니다.
-
- 방문 신청 버튼을 눌러 출입 권한을 신청해주세요.
-
- >
- )}
-
-
+
From 464be253d37626d91c4a0d70f81d9dc1fa8ca9d2 Mon Sep 17 00:00:00 2001
From: Jiwon Chae <63784453+jiwon0226@users.noreply.github.com>
Date: Tue, 13 May 2025 13:24:59 +0900
Subject: [PATCH 2/3] =?UTF-8?q?KW-157/feat=20:=20=EC=B9=B4=EB=93=9C=20?=
=?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
components/cards/QrCard.js | 11 +++--
components/cards/QrCards.js | 41 ++++++++++++++++
components/cards/styles/QrCard.styles.js | 4 +-
pages/MainPage.js | 34 ++++++++-----
pages/styles/MainPage.styles.js | 62 +-----------------------
5 files changed, 73 insertions(+), 79 deletions(-)
diff --git a/components/cards/QrCard.js b/components/cards/QrCard.js
index bea7dd1..3ee8a62 100644
--- a/components/cards/QrCard.js
+++ b/components/cards/QrCard.js
@@ -6,15 +6,18 @@ import QRCode from 'react-native-qrcode-svg';
import NormalButton from '../../components/buttons/NormalButton';
import { styles } from './styles/QrCard.styles';
import { colors } from '../../constants/colors';
+import { hospitalName } from '../../mocks/hospitalData';
// hasAccessAuthority: 출입 권한 여부, userVC : VC에 담을 사용자 정보, qrData : QR에 담을 JSON 문자열
-const QrCard = ({ hasAccessAuthority, userVC, qrData }) => {
+const QrCard = ({ hasAccessAuthority, did, userName, hospitalName }) => {
// 해당 QR의 상세 페이지로 이동 (아직 미구현)
//const navigation = useNavigation();
// const navigateToAccessListDeatail = () => {
// navigation.navigate('AccessListDetailPage');
// };
+ // 임시: QR에 담을 JSON 문자열
+ const qrData = JSON.stringify({ did, userName, hospitalName });
return (
@@ -27,10 +30,8 @@ const QrCard = ({ hasAccessAuthority, userVC, qrData }) => {
<>
임시 출입 QR
- {userVC.userName}
- {userVC.hospital1}
- {userVC.hospital2}
- {userVC.hospital3}
+ {userName}
+ {hospitalName}
>
) : (
<>
diff --git a/components/cards/QrCards.js b/components/cards/QrCards.js
index e69de29..4038671 100644
--- a/components/cards/QrCards.js
+++ b/components/cards/QrCards.js
@@ -0,0 +1,41 @@
+import React from 'react';
+import { FlatList, View, Dimensions } from 'react-native';
+import QrCard from './QrCard';
+
+const { width } = Dimensions.get('window');
+
+const QrCards = ({ userVC, hasAccessAuthority }) => {
+ // 권한 없거나 카드 데이터 없으면 안내 메시지 카드만
+ if (!hasAccessAuthority || !userVC || userVC.length === 0) {
+ return (
+
+
+
+ );
+ }
+
+ // 카드 리스트
+ return (
+
+ item.did}
+ horizontal //가로 스크롤
+ pagingEnabled //한 페이지씩 스크롤
+ showsHorizontalScrollIndicator={false} //하단 기본 스크롤바 숨김
+ renderItem={({ item }) => (
+
+
+
+ )}
+ />
+
+ );
+};
+
+export default QrCards;
diff --git a/components/cards/styles/QrCard.styles.js b/components/cards/styles/QrCard.styles.js
index 87200cb..45c6505 100644
--- a/components/cards/styles/QrCard.styles.js
+++ b/components/cards/styles/QrCard.styles.js
@@ -10,8 +10,8 @@ export const styles = StyleSheet.create({
shadowRadius: 5,
elevation: 7, // Android용
borderRadius: 15,
- width: '100%',
- height: '55%',
+ width: '80%',
+ height: '80%',
marginVertical: '10%',
},
cardContainer: {
diff --git a/pages/MainPage.js b/pages/MainPage.js
index 85d66de..967dbe3 100644
--- a/pages/MainPage.js
+++ b/pages/MainPage.js
@@ -5,23 +5,35 @@ import NormalButton from '../components/buttons/NormalButton';
import { styles } from './styles/MainPage.styles';
import QRCode from 'react-native-qrcode-svg';
import { colors } from '../constants/colors';
-import QrCard from '../components/cards/QrCard';
+import QrCards from '../components/cards/QrCards';
const MainPage = () => {
// 임시: 상태변수로 출입 권한 제어
const [hasAccessAuthority, setHasAccessAuthority] = useState(true);
// 임시: VC에 담을 사용자 정보
- const userVC = {
- did: 'did:example:123456789abcdefghi',
- userName: '김짱구',
- hospital1: '짱구병원',
- hospital2: '흰둥이병원',
- hospital3: '오수병원',
- issuedAt: Date.now(),
- };
+ const userVC = [
+ {
+ did: 'did:example:123456789abcdefghi',
+ userName: '김짱구',
+ hospitalName: '짱구병원',
+ issuedAt: Date.now(),
+ },
+ {
+ did: 'did:example:123456789abcdefdhi',
+ userName: '김짱구',
+ hospitalName: '흰둥이병원',
+ issuedAt: Date.now(),
+ },
+ {
+ did: 'did:example:123456789abcdeffhi',
+ userName: '김짱구',
+ hospitalName: '오수병원',
+ issuedAt: Date.now(),
+ },
+ ];
// 임시: QR에 담을 JSON 문자열
- const qrData = JSON.stringify(userVC);
+ //const qrData = JSON.stringify(userVC);
const navigation = useNavigation();
@@ -40,7 +52,7 @@ const MainPage = () => {
source={require('../assets/images/logoGreen.png')}
resizeMode="contain" // 이미지 비율 유지
/>
-
+
diff --git a/pages/styles/MainPage.styles.js b/pages/styles/MainPage.styles.js
index 9321614..60e6bc4 100644
--- a/pages/styles/MainPage.styles.js
+++ b/pages/styles/MainPage.styles.js
@@ -4,7 +4,7 @@ import { colors } from '../../constants/colors';
export const styles = StyleSheet.create({
container: {
flex: 1,
- paddingHorizontal: '10%',
+ // paddingHorizontal: '10%',
paddingTop: '5%',
},
logoImage: {
@@ -13,66 +13,6 @@ export const styles = StyleSheet.create({
marginTop: '15%',
alignSelf: 'center',
},
- shadowWrapper: {
- // 그림자 설정
- shadowColor: 'black',
- shadowOffset: { width: 0, height: 2 },
- shadowOpacity: 0.2,
- shadowRadius: 5,
- elevation: 7, // Android용
- borderRadius: 15,
- width: '100%',
- height: '55%',
- marginVertical: '10%',
- },
- cardContainer: {
- flex: 1, // 부모(shadowWrapper)의 크기를 꽉 채워 카드와 그림자 모양을 일치시킴
- backgroundColor: colors.white,
- borderRadius: 15,
- padding: '10%',
- alignItems: 'center',
- justifyContent: 'center',
- overflow: 'hidden', // 배경 이미지가 카드 안에 잘리게
- position: 'relative', // 자식의 absolute 포지션 기준점
- },
- backgroundImage: {
- ...StyleSheet.absoluteFillObject, // 전체 카드 덮게 만듦
- width: '125%',
- zIndex: 0, // 맨 뒤로
- opacity: 0.5,
- },
- cardText: {
- fontSize: 20,
- fontWeight: 600,
- color: colors.black,
- textAlign: 'center',
- marginBottom: '5%',
- },
- cardSubText: {
- fontSize: 16,
- fontWeight: 500,
- color: colors.darkGray,
- textAlign: 'center',
- },
- qrTitle: {
- fontSize: 26,
- fontWeight: 700,
- color: colors.black,
- marginBottom: '10%',
- zIndex: 1, // QR과 텍스트를 배경 위에
- },
- userName: {
- fontSize: 24,
- fontWeight: 600,
- color: colors.black,
- marginVertical: '8%',
- },
- hospital: {
- fontSize: 16,
- fontWeight: 500,
- color: colors.darkGray,
- marginTop: '2%',
- },
buttonContainer: {
flexDirection: 'row',
justifyContent: 'center',
From 412b3b667e0b38c5ab3c46550d9397c82ba508b2 Mon Sep 17 00:00:00 2001
From: Jiwon Chae <63784453+jiwon0226@users.noreply.github.com>
Date: Tue, 13 May 2025 15:09:16 +0900
Subject: [PATCH 3/3] =?UTF-8?q?KW-157/feat:=20=EC=B9=B4=EB=93=9C=EB=A6=AC?=
=?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98?=
=?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20dot=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app.config.js | 2 +-
components/cards/Dot.js | 36 ++++++++++++++++
components/cards/QrCards.js | 52 ++++++++++++++++++++---
components/cards/styles/Dot.styles.js | 10 +++++
components/cards/styles/QrCard.styles.js | 2 +-
components/cards/styles/QrCards.styles.js | 11 +++++
pages/styles/MainPage.styles.js | 3 +-
7 files changed, 107 insertions(+), 9 deletions(-)
create mode 100644 components/cards/Dot.js
create mode 100644 components/cards/styles/Dot.styles.js
diff --git a/app.config.js b/app.config.js
index cfb5823..374b754 100644
--- a/app.config.js
+++ b/app.config.js
@@ -25,7 +25,7 @@ export default {
favicon: './assets/images/logoIcon.png',
},
extra: {
- BASE_URL: 'http://192.168.0.225:8081', // 본인 pc IPv4 주소로 수정하세용
+ BASE_URL: 'http://192.168.0.181:8081', // 본인 pc IPv4 주소로 수정하세용
},
},
};
diff --git a/components/cards/Dot.js b/components/cards/Dot.js
new file mode 100644
index 0000000..ede8791
--- /dev/null
+++ b/components/cards/Dot.js
@@ -0,0 +1,36 @@
+import React, { useEffect, useRef } from 'react';
+import { Animated, StyleSheet } from 'react-native';
+import { styles } from './styles/Dot.styles';
+import { colors } from '../../constants/colors';
+
+// dot의 기본 너비와 활성화(선택) 상태일 때의 너비
+const DOT_WIDTH = 10;
+const DOT_ACTIVE_WIDTH = 16;
+
+const Dot = ({ active }) => {
+ // dot width를 위한 Animated.Value 배열
+ const animatedWidth = useRef(new Animated.Value(active ? DOT_ACTIVE_WIDTH : DOT_WIDTH)).current;
+
+ // pageIndex가 바뀔 때 dot width 애니메이션
+ useEffect(() => {
+ Animated.timing(animatedWidth, {
+ toValue: active ? DOT_ACTIVE_WIDTH : DOT_WIDTH,
+ duration: 300,
+ useNativeDriver: false,
+ }).start();
+ }, [active, animatedWidth]);
+
+ return (
+
+ );
+};
+
+export default Dot;
diff --git a/components/cards/QrCards.js b/components/cards/QrCards.js
index 4038671..5dfc9b1 100644
--- a/components/cards/QrCards.js
+++ b/components/cards/QrCards.js
@@ -1,10 +1,19 @@
-import React from 'react';
-import { FlatList, View, Dimensions } from 'react-native';
+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';
+// 화면의 가로 길이 가져오기
const { width } = Dimensions.get('window');
+const CARD_WIDTH = width;
+const SIDE_PADDING = (width - CARD_WIDTH) / 2; // 좌우 패딩 계산
+const OVERLAP = 80; // 카드가 겹치는 정도
const QrCards = ({ userVC, hasAccessAuthority }) => {
+ const [pageIndex, setPageIndex] = useState(0);
+ const flatListRef = useRef(null);
+
// 권한 없거나 카드 데이터 없으면 안내 메시지 카드만
if (!hasAccessAuthority || !userVC || userVC.length === 0) {
return (
@@ -14,17 +23,42 @@ const QrCards = ({ userVC, hasAccessAuthority }) => {
);
}
+ // 스크롤이 끝났을 때 현재 페이지 인덱스 계산
+ const onMomentumScrollEnd = (event) => {
+ const offsetX = event.nativeEvent.contentOffset.x;
+ const newIndex = Math.round(offsetX / (CARD_WIDTH - OVERLAP));
+ setPageIndex(newIndex);
+ };
+
+ // dot(인디케이터) 클릭 시 해당 카드로 이동
+ const handleDotPress = (index) => {
+ flatListRef.current?.scrollToIndex({ index, animated: true });
+ };
+
// 카드 리스트
return (
item.did}
horizontal //가로 스크롤
- pagingEnabled //한 페이지씩 스크롤
showsHorizontalScrollIndicator={false} //하단 기본 스크롤바 숨김
- renderItem={({ item }) => (
-
+ pagingEnabled={false} // snapToInterval을 사용하므로 false
+ snapToInterval={CARD_WIDTH - OVERLAP} // 카드 단위로 스냅
+ decelerationRate="fast" // 빠른 스냅 효과
+ contentContainerStyle={{
+ paddingHorizontal: SIDE_PADDING, // 양쪽에 패딩 추가로 옆 카드 살짝 보이게
+ }}
+ renderItem={({ item, index }) => (
+
{
/>
)}
+ onMomentumScrollEnd={onMomentumScrollEnd}
/>
+
+ {userVC.map((_, i) => (
+ handleDotPress(i)}>
+
+
+ ))}
+
);
};
diff --git a/components/cards/styles/Dot.styles.js b/components/cards/styles/Dot.styles.js
new file mode 100644
index 0000000..5d09691
--- /dev/null
+++ b/components/cards/styles/Dot.styles.js
@@ -0,0 +1,10 @@
+import { StyleSheet } from 'react-native';
+import { colors } from '../../../constants/colors';
+
+export const styles = StyleSheet.create({
+ dot: {
+ height: 10,
+ borderRadius: 16,
+ marginHorizontal: 4,
+ },
+});
diff --git a/components/cards/styles/QrCard.styles.js b/components/cards/styles/QrCard.styles.js
index 45c6505..7f13ae1 100644
--- a/components/cards/styles/QrCard.styles.js
+++ b/components/cards/styles/QrCard.styles.js
@@ -10,7 +10,7 @@ export const styles = StyleSheet.create({
shadowRadius: 5,
elevation: 7, // Android용
borderRadius: 15,
- width: '80%',
+ width: '70%',
height: '80%',
marginVertical: '10%',
},
diff --git a/components/cards/styles/QrCards.styles.js b/components/cards/styles/QrCards.styles.js
index e69de29..0502f92 100644
--- a/components/cards/styles/QrCards.styles.js
+++ b/components/cards/styles/QrCards.styles.js
@@ -0,0 +1,11 @@
+import { StyleSheet } from 'react-native';
+
+const styles = StyleSheet.create({
+ dotContainer: {
+ flexDirection: 'row',
+ justifyContent: 'center',
+ marginBottom: '5%',
+ },
+});
+
+export default styles;
diff --git a/pages/styles/MainPage.styles.js b/pages/styles/MainPage.styles.js
index 60e6bc4..091dddd 100644
--- a/pages/styles/MainPage.styles.js
+++ b/pages/styles/MainPage.styles.js
@@ -4,7 +4,6 @@ import { colors } from '../../constants/colors';
export const styles = StyleSheet.create({
container: {
flex: 1,
- // paddingHorizontal: '10%',
paddingTop: '5%',
},
logoImage: {
@@ -17,6 +16,6 @@ export const styles = StyleSheet.create({
flexDirection: 'row',
justifyContent: 'center',
marginTop: '3%',
- gap: '10%',
+ gap: '5%',
},
});