From 6c06e584646951f4633295e9fd394fceb11dc417 Mon Sep 17 00:00:00 2001 From: hyeongmin Kim <113012760+gudmin0526@users.noreply.github.com> Date: Fri, 14 Oct 2022 14:12:00 +0000 Subject: [PATCH 01/48] Feat: #87 Apply updateUserApi --- back-end/server.js | 9 +- front-end/app/src/apis/updateUserApi.js | 16 ++ front-end/app/src/assets/images/arrow.png | Bin 0 -> 959 bytes .../app/src/components/ReportGroup/index.js | 22 +-- .../app/src/components/ReportGroup/style.js | 12 +- front-end/app/src/data/ranks.js | 36 ++-- .../app/src/screens/SignUpScreen/index.js | 11 +- .../screens/setting-screens/UserAddScreen.js | 167 +++++++++--------- .../screens/setting-screens/UserMgtScreen.js | 34 +--- .../setting-screens/UserUpdateScreen.js | 158 +++++++++++++++++ 10 files changed, 314 insertions(+), 151 deletions(-) create mode 100644 front-end/app/src/apis/updateUserApi.js create mode 100644 front-end/app/src/assets/images/arrow.png create mode 100644 front-end/app/src/screens/setting-screens/UserUpdateScreen.js diff --git a/back-end/server.js b/back-end/server.js index 435d2df2..1064bde6 100644 --- a/back-end/server.js +++ b/back-end/server.js @@ -5,6 +5,10 @@ const cors = require("cors"); const userRoutes = require("./routes/userRoutes"); const chatRoutes = require("./routes/chatRoutes"); const messageRoutes = require("./routes/messageRoutes"); +const unitRoutes = require("./routes/unitRoutes"); +const reportRoutes = require("./routes/reportRoutes"); +const commentRoutes = require("./routes/commentRoutes"); + const { notFound, errorHandler } = require("./middleware/errorMiddleware"); const path = require("path"); @@ -26,7 +30,6 @@ app.use("/api/unit", unitRoutes); app.use("/api/report", reportRoutes); app.use("/api/comment", commentRoutes); - /*const __dirname1 = path.resolve(); if (process.env.NODE_ENV === "production") { @@ -42,7 +45,6 @@ app.get("/", (req, res) => { }); //} - // Error Handling middlewares app.use(notFound); app.use(errorHandler); @@ -59,7 +61,7 @@ const io = require("socket.io")(server, { cors: { //origin: "http://localhost:3000", // credentials: true, - origin: "*" + origin: "*", }, }); @@ -94,4 +96,3 @@ io.on("connection", (socket) => { socket.leave(userData._id); }); }); - diff --git a/front-end/app/src/apis/updateUserApi.js b/front-end/app/src/apis/updateUserApi.js new file mode 100644 index 00000000..d3f37a9e --- /dev/null +++ b/front-end/app/src/apis/updateUserApi.js @@ -0,0 +1,16 @@ +import URL from '../../url' + +const updateUserApi = async ({ Rank, Name, email, milNumber, Number }) => { + try { + const res = await fetch(URL + '/api/user/update', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ Rank, Name, email, milNumber, Number }), + }) + return res.json() + } catch (error) { + console.log(error) + } +} diff --git a/front-end/app/src/assets/images/arrow.png b/front-end/app/src/assets/images/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..e21eed563663f109135fd19d214e2801bc9ab505 GIT binary patch literal 959 zcmeAS@N?(olHy`uVBq!ia0vp^4?&oN8Ax*GDtQ2@q5z)|*Z=?j1DOvVJh*!G>aAP1 zjvP5MbLLDdD=RlQw?BXW)YQ~)aB!SEcka`tPtTt}7ZDNJxpU`)2@{?@d)C(0ws7G> zBO@avC8g--=#-R{(9lqRe*WCt+;88$?cKZA(a~|`%9Y;U-g0tsjg5_^rKNg$dK)%u za4zQk%fP_Q;pyTSQZeW4+>=F*90Xi4%@oZxzh_H%@W1}z;Ug72Q_swax_B^n-)jA- zirZr&V?*y|NF?_d9>YSko!)WPPu6Malj#CZW!|!Gtulx6H-)`&SoKI`-;Ms@<3YU7 zKlqya%leAy$cwaHt$tOYl^|Pp;ql){**2lSfv+Yc8S8rUbYD?Cnr5Woy{9bbxX8>J zz4?WAePlyYW=UVPuwTNbWpsFvPGNzUY;cZPl}!7}oa;i(x45j^E7}_zrF6Yg z+xw0$Q0weZ|%H{H_Q4o&4exc@=fBWX4~ys`g7IIIFm;;R|_V4uiw z+U*sG)^fJ{0l{)&-TOE14A`{$;tcVXhdU12|Ce_vnic7-eR4;n5d*25+&V9xF`^_ir`#ovjev$pn)AqT~*vCC<-+Af%ljrUWpa0K{>2EFf zA8FMe1n-(_dY3cow||rSM(-q=@uyF cbN44p+zR844dFAE0<$55r>mdKI;Vst0G+nc#{d8T literal 0 HcmV?d00001 diff --git a/front-end/app/src/components/ReportGroup/index.js b/front-end/app/src/components/ReportGroup/index.js index 1ef0a394..8b1e76db 100644 --- a/front-end/app/src/components/ReportGroup/index.js +++ b/front-end/app/src/components/ReportGroup/index.js @@ -1,20 +1,14 @@ import React from 'react' -import { FlatList, Text, View, TouchableOpacity } from 'react-native' +import { FlatList, Text, View, TouchableOpacity, Image } from 'react-native' import { Avatar } from 'react-native-paper' import { styles } from './style' import { useNunitoFonts } from '../../hooks/useNunitoFonts' const ItemSeparator = () => ( - - - + ) @@ -24,19 +18,19 @@ const renderItem = ({ item }) => ( {item.name} {item.position} - + {/* - + */} ) diff --git a/front-end/app/src/components/ReportGroup/style.js b/front-end/app/src/components/ReportGroup/style.js index e92c4e12..aff004a0 100644 --- a/front-end/app/src/components/ReportGroup/style.js +++ b/front-end/app/src/components/ReportGroup/style.js @@ -7,10 +7,12 @@ export const styles = StyleSheet.create({ }, view: { borderWidth: 1, - borderRadius: 10, + borderRadius: 2, borderColor: Colors.grey800, alignItems: 'center', - padding: 4, + paddingVertical: 4, + width: 70, + marginVertical: 5, }, image: { marginBottom: 5, @@ -22,8 +24,8 @@ export const styles = StyleSheet.create({ }, text: { fontFamily: 'NunitoSans_300Light', - color: Colors.grey800, - fontSize: 12, - marginBottom: 10, + color: Colors.grey600, + fontSize: 13, + marginBottom: 14, }, }) diff --git a/front-end/app/src/data/ranks.js b/front-end/app/src/data/ranks.js index 65b89e39..0806fefc 100644 --- a/front-end/app/src/data/ranks.js +++ b/front-end/app/src/data/ranks.js @@ -1,22 +1,22 @@ const RankItems = [ - { label: '대장', value: 'GEN' }, - { label: '준장', value: 'LG' }, - { label: '소장', value: 'MG' }, - { label: '대령', value: 'BG' }, - { label: '중령', value: 'COL' }, - { label: '소령', value: 'LTC' }, - { label: '대위', value: 'MAJ' }, - { label: '중위', value: 'CPT' }, - { label: '소위', value: 'LIU' }, - { label: '준위', value: 'SECLIU' }, - { label: '원사', value: 'SGM' }, - { label: '상사', value: 'MST' }, - { label: '중사', value: 'SFC' }, - { label: '하사', value: 'SST' }, - { label: '병장', value: 'SGT' }, - { label: '상병', value: 'CPL' }, - { label: '일병', value: 'PFC' }, - { label: '이병', value: 'PVT' }, + { label: '대장', value: '대장' }, + { label: '준장', value: '준장' }, + { label: '소장', value: '소장' }, + { label: '대령', value: '대령' }, + { label: '중령', value: '중령' }, + { label: '소령', value: '소령' }, + { label: '대위', value: '대위' }, + { label: '중위', value: '중위' }, + { label: '소위', value: '소위' }, + { label: '준위', value: '준위' }, + { label: '원사', value: '원사' }, + { label: '상사', value: '상사' }, + { label: '중사', value: '중사' }, + { label: '하사', value: '하사' }, + { label: '병장', value: '병장' }, + { label: '상병', value: '상병' }, + { label: '일병', value: '일병' }, + { label: '이병', value: '이병' }, ] export default RankItems diff --git a/front-end/app/src/screens/SignUpScreen/index.js b/front-end/app/src/screens/SignUpScreen/index.js index 9070257d..4422cbdd 100644 --- a/front-end/app/src/screens/SignUpScreen/index.js +++ b/front-end/app/src/screens/SignUpScreen/index.js @@ -3,6 +3,7 @@ import { TextInput } from 'react-native-paper' // prettier-ignore import { View ,SafeAreaView, TouchableOpacity, ScrollView, Text, Alert } from 'react-native' import { styles } from './style' +import { useNavigation } from '@react-navigation/native' import { GuideText } from '../../components/GuideText' import RankItems from '../../data/ranks' import DropDownPicker from 'react-native-dropdown-picker' @@ -18,10 +19,14 @@ const checkPasswordMatch = (password, confirmPassword) => { } export function SignUpScreen() { + const navigation = useNavigation() + const registerHandler = useCallback(async (userData) => { const res = await registerApi(userData) - if (res.token) Alert.alert('회원가입에 성공하였습니다.') - else Alert.alert(res.message) + if (res.token) { + Alert.alert('회원가입에 성공하였습니다.') + navigation.navigate('LoginScreen') + } else Alert.alert(res.message) }) const [RankOpen, setRankOpen] = useState(false) @@ -128,7 +133,7 @@ export function SignUpScreen() { {Rank && - id && + DoDID && password && password === confirmPassword && Name && diff --git a/front-end/app/src/screens/setting-screens/UserAddScreen.js b/front-end/app/src/screens/setting-screens/UserAddScreen.js index fb7cc9df..79d920b7 100644 --- a/front-end/app/src/screens/setting-screens/UserAddScreen.js +++ b/front-end/app/src/screens/setting-screens/UserAddScreen.js @@ -19,15 +19,15 @@ export function UserAddScreen() { const res = await addUserApi({ Rank, Name, DoDID, Type }) if (res.Invcode) Alert.alert( - `사용자 등록에 성공했습니다, 초대 코드는 ${res.Invcode}입니다.` + `사용자 등록에 성공했습니다.\n초대 코드는 ${res.Invcode}입니다.` ) else Alert.alert(res.message) - cb() + console.log(res.message) } const [DoDID, setDoDID] = useState('') const [Name, setName] = useState('') - const [role, setRole] = useState('') + const [Position, setPosition] = useState('') const [RankOpen, setRankOpen] = useState(false) const [Rank, setRank] = useState(null) @@ -39,83 +39,89 @@ export function UserAddScreen() { return ( - - setDoDID(DoDID)} - style={styles.textInput} - > - - - - - - - - setName(Name)} - style={styles.textInput} - > - - - - - - - - setRole(role)} - style={styles.textInput} - > - - - + + setDoDID(DoDID)} + style={styles.textInput} + > + + - {DoDID && Rank && Name && AccountType && role && ( - - addUserHandler({ Rank, Name, DoDID, Type: AccountType }) - } - /> - )} + + + + + setName(Name)} + style={styles.textInput} + > + + + + + + + + setPosition(Position)} + style={styles.textInput} + > + + + + + {DoDID && Rank && Name && AccountType && Position && ( + + addUserHandler({ + Rank, + Name, + DoDID, + Type: AccountType, + Position, + }) + } + /> + )} ) } @@ -126,9 +132,6 @@ const styles = StyleSheet.create({ backgroundColor: 'white', alignItems: 'center', }, - scrollView: { - width: '100%', - }, guideTextView: { marginBottom: (15 / 812) * window.height, width: '100%', diff --git a/front-end/app/src/screens/setting-screens/UserMgtScreen.js b/front-end/app/src/screens/setting-screens/UserMgtScreen.js index 764addb8..8840072e 100644 --- a/front-end/app/src/screens/setting-screens/UserMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/UserMgtScreen.js @@ -2,6 +2,8 @@ import React from 'react' import { FAB, List, Avatar } from 'react-native-paper' import { SafeAreaView, StyleSheet, ScrollView } from 'react-native' import { useNavigation } from '@react-navigation/native' +import { ReportGroup } from '../../components/ReportGroup' +import DATA from '../../data/procData' const LeftImage = () => ( - - {tempData.map((user, idx) => ( - ( - deleteUserHandler()} - /> - )} - titleStyle={styles.titleStyle} - descriptionStyle={styles.descriptionStyle} - key={idx} - onPress={() => - props.showModal({ - name: user.title, - role: user.description, - team: '통신소대', - tel: '010-1234-5678', - }) - } - /> - ))} + + + { + const res = await updateUserApi({ + Rank, + Name, + email, + milNumber, + Number, + }) + if (res.message) Alert.alert(res.message) + else { + setUserMe({ ...userMe, Rank, Name, email, milNumber, Number }) + Alert.alert('사용자 정보가 변경되었습니다.') + } + } + ) + + const [Name, setName] = useState(userMe.Name) + const [email, setEmail] = useState(userMe.email) + const [Number, setNumber] = useState(userMe.Number) + const [milNumber, setMilNumber] = useState(userMe.milNumber) + + const [RankOpen, setRankOpen] = useState(false) + const [Rank, setRank] = useState(userMe.Rank) + const [Ranks, setRanks] = useState(RankItems) + + return ( + + + + + + + setName(Name)} + style={styles.textInput} + > + + + + setEmail(email)} + style={styles.textInput} + > + + + + + + + setNumber(Number)} + style={styles.textInput} + > + + + + setMilNumber(milNumber)} + style={styles.textInput} + > + + + + + {DoDID && Rank && Name && AccountType && Position && ( + + updateUserHandler({ + Rank, + Name, + email, + Number, + milNumber, + }) + } + /> + )} + + ) +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: 'white', + alignItems: 'center', + }, + guideTextView: { + marginBottom: (15 / 812) * window.height, + width: '100%', + alignItems: 'flex-end', + }, + view: { + width: '85%', + }, + textInput: { + width: '100%', + backgroundColor: 'white', + }, + dropDown: { + width: '100%', + backgroundColor: 'white', + borderWidth: 0, + borderBottomWidth: 1, + borderColor: Colors.grey400, + }, + fab: { + borderRadius: 60, + height: 56, + width: 56, + position: 'absolute', + bottom: 25, + right: 20, + }, +}) From ef197d312bfaea7388bc87e3f0fff5d06f539e3d Mon Sep 17 00:00:00 2001 From: hyeongmin Kim <113012760+gudmin0526@users.noreply.github.com> Date: Fri, 14 Oct 2022 14:51:38 +0000 Subject: [PATCH 02/48] Feat: #88 Create User search Api --- front-end/app/src/apis/searchUserApi.js | 13 +++++++++++++ front-end/app/src/apis/updateUserApi.js | 2 ++ .../screens/report-screens/CreateReportScreen.js | 8 +++++++- .../src/screens/setting-screens/UserUpdateScreen.js | 1 + 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 front-end/app/src/apis/searchUserApi.js diff --git a/front-end/app/src/apis/searchUserApi.js b/front-end/app/src/apis/searchUserApi.js new file mode 100644 index 00000000..78f0f50c --- /dev/null +++ b/front-end/app/src/apis/searchUserApi.js @@ -0,0 +1,13 @@ +import URL from '../../url' + +const searchUserApi = async ({ Name, DoDID, email }) => { + const query = Name || DoDID || email ? Name || DoDID || email : '' + try { + const res = await fetch(URL + 'api/user?search=' + query) + return res.json() + } catch (error) { + console.log(error) + } +} + +export default searchUserApi diff --git a/front-end/app/src/apis/updateUserApi.js b/front-end/app/src/apis/updateUserApi.js index d3f37a9e..be096d74 100644 --- a/front-end/app/src/apis/updateUserApi.js +++ b/front-end/app/src/apis/updateUserApi.js @@ -14,3 +14,5 @@ const updateUserApi = async ({ Rank, Name, email, milNumber, Number }) => { console.log(error) } } + +export default updateUserApi diff --git a/front-end/app/src/screens/report-screens/CreateReportScreen.js b/front-end/app/src/screens/report-screens/CreateReportScreen.js index 00e9bd20..bfcf89c3 100644 --- a/front-end/app/src/screens/report-screens/CreateReportScreen.js +++ b/front-end/app/src/screens/report-screens/CreateReportScreen.js @@ -14,6 +14,8 @@ export function CreateReportScreen() { const navigation = useNavigation() + const [query, setQuery] = useState('') + const [typeOpen, setTypeOpen] = useState(false) const [type, setType] = useState('') const [typeItem, setTypeItem] = useState([ @@ -89,7 +91,11 @@ export function CreateReportScreen() { style={[styles.width90, groups.length === 0 && { marginTop: 15 }]} > 추가된 인원 - + setQuery(query)} + /> 내용 diff --git a/front-end/app/src/screens/setting-screens/UserUpdateScreen.js b/front-end/app/src/screens/setting-screens/UserUpdateScreen.js index 238e945c..49a34132 100644 --- a/front-end/app/src/screens/setting-screens/UserUpdateScreen.js +++ b/front-end/app/src/screens/setting-screens/UserUpdateScreen.js @@ -6,6 +6,7 @@ import { GuideText } from '../../components/GuideText' import { window } from '../../constants/layout' import DropDownPicker from 'react-native-dropdown-picker' import { MyButton } from '../../components/MyButton' +import updateUserApi from '../../apis/updateUserApi' import { userState } from '../../states/userState' import { useRecoilState } from 'recoil' From 9c3685aa38c9bd2987c9868942766acf5bb58023 Mon Sep 17 00:00:00 2001 From: hyeongmin Kim <113012760+gudmin0526@users.noreply.github.com> Date: Sun, 16 Oct 2022 06:02:54 +0000 Subject: [PATCH 03/48] Refactor: Remove Notification Screen --- front-end/app/src/navigation/TabNavigator.js | 70 +++++++++---------- .../app/src/screens/NotificationScreen.js | 9 --- front-end/app/src/screens/index.js | 1 - .../screens/setting-screens/UserMgtScreen.js | 15 ++-- front-end/app/url.js | 2 +- 5 files changed, 40 insertions(+), 57 deletions(-) delete mode 100644 front-end/app/src/screens/NotificationScreen.js diff --git a/front-end/app/src/navigation/TabNavigator.js b/front-end/app/src/navigation/TabNavigator.js index 4bb97827..a988e571 100644 --- a/front-end/app/src/navigation/TabNavigator.js +++ b/front-end/app/src/navigation/TabNavigator.js @@ -1,77 +1,71 @@ -import React from 'react' -import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' -import { Colors } from 'react-native-paper' -import Icon from 'react-native-vector-icons/MaterialCommunityIcons' -import { ReportNavigator } from './ReportNavigator' -import { SettingNavigator } from './SettingNavigator' -import { ChatListScreen, OrgChartScreen, NotificationScreen } from '../screens' +import React from "react"; +import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; +import { Colors } from "react-native-paper"; +import Icon from "react-native-vector-icons/MaterialCommunityIcons"; +import { ReportNavigator } from "./ReportNavigator"; +import { SettingNavigator } from "./SettingNavigator"; +import { ChatListScreen, OrgChartScreen } from "../screens"; -const Tab = createBottomTabNavigator() +const Tab = createBottomTabNavigator(); const icons = { - ReportNavigator: ['note-text', 'note-text-outline'], - ChatListScreen: ['message-text', 'message-text-outline'], - OrgChartScreen: ['graph', 'graph-outline'], - NotificationScreen: ['bell', 'bell-outline'], - SettingNavigator: ['cog', 'cog-outline'], -} + ReportNavigator: ["note-text", "note-text-outline"], + ChatListScreen: ["message-text", "message-text-outline"], + OrgChartScreen: ["graph", "graph-outline"], + SettingNavigator: ["cog", "cog-outline"], +}; const getActiveRouteName = (route) => { if (route.state) { - return getActiveRouteName(route.state.routes[route.state.index]) + return getActiveRouteName(route.state.routes[route.state.index]); } - return route.name -} + return route.name; +}; const screenOptions = ({ route }) => { return { tabBarIcon: ({ focused, size }) => { - const { name } = route - const focusedSize = focused ? size + 6 : size - const focusedColor = focused ? Colors.white : Colors.grey400 - const [icon, iconOutline] = icons[name] - const iconName = focused ? icon : iconOutline - return + const { name } = route; + const focusedSize = focused ? size + 6 : size; + const focusedColor = focused ? Colors.white : Colors.grey400; + const [icon, iconOutline] = icons[name]; + const iconName = focused ? icon : iconOutline; + return ; }, tabBarShowLabel: true, - headerTitleAlign: 'center', - tabBarStyle: { height: 55, paddingBottom: 5, backgroundColor: '#008272' }, + headerTitleAlign: "center", + tabBarStyle: { height: 55, paddingBottom: 5, backgroundColor: "#008272" }, tabBarLabelStyle: { color: Colors.grey200 }, - } -} + }; +}; export function TabNavigator() { return ( - - ) + ); } diff --git a/front-end/app/src/screens/NotificationScreen.js b/front-end/app/src/screens/NotificationScreen.js deleted file mode 100644 index 9b5ed3a2..00000000 --- a/front-end/app/src/screens/NotificationScreen.js +++ /dev/null @@ -1,9 +0,0 @@ -import { View, Text } from 'react-native' - -export function NotificationScreen() { - return ( - - Notification - - ) -} diff --git a/front-end/app/src/screens/index.js b/front-end/app/src/screens/index.js index 184e9066..4c45e2e4 100644 --- a/front-end/app/src/screens/index.js +++ b/front-end/app/src/screens/index.js @@ -9,5 +9,4 @@ export * from './report-screens/ReportScreen' export * from './report-screens/SentReportScreen' export * from './chat-screens/ChatListScreen' export * from './chat-screens/ChatRoomScreen' -export * from './NotificationScreen' export * from './OrgChartScreen' diff --git a/front-end/app/src/screens/setting-screens/UserMgtScreen.js b/front-end/app/src/screens/setting-screens/UserMgtScreen.js index 8840072e..5d5368bf 100644 --- a/front-end/app/src/screens/setting-screens/UserMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/UserMgtScreen.js @@ -1,9 +1,7 @@ import React from 'react' -import { FAB, List, Avatar } from 'react-native-paper' +import { FAB, Avatar } from 'react-native-paper' import { SafeAreaView, StyleSheet, ScrollView } from 'react-native' import { useNavigation } from '@react-navigation/native' -import { ReportGroup } from '../../components/ReportGroup' -import DATA from '../../data/procData' const LeftImage = () => ( ( const tempData = [ { - Name: '김형민', - position: '본부중대 통신', + title: '중위 이원빈', + description: '통신소대장', + }, + { + title: '중사 구창우', + description: '통신부소대장', }, ] @@ -28,8 +30,6 @@ export function UserMgtScreen() { return ( - - Date: Sun, 16 Oct 2022 07:18:10 +0000 Subject: [PATCH 04/48] Design: User Management Screen --- front-end/app/src/apis/searchUserApi.js | 13 ++- .../app/src/components/MyButton/style.js | 1 + .../screens/setting-screens/UserAddScreen.js | 28 +++---- .../screens/setting-screens/UserMgtScreen.js | 81 ++++++++++++++----- 4 files changed, 85 insertions(+), 38 deletions(-) diff --git a/front-end/app/src/apis/searchUserApi.js b/front-end/app/src/apis/searchUserApi.js index 78f0f50c..44d9eb42 100644 --- a/front-end/app/src/apis/searchUserApi.js +++ b/front-end/app/src/apis/searchUserApi.js @@ -1,9 +1,16 @@ import URL from '../../url' +import asyncStorage from '@react-native-async-storage/async-storage' -const searchUserApi = async ({ Name, DoDID, email }) => { - const query = Name || DoDID || email ? Name || DoDID || email : '' +const searchUserApi = async (query) => { + const searchQuery = query ? query : '' + console.log(URL + '/api/user?search=' + searchQuery) try { - const res = await fetch(URL + 'api/user?search=' + query) + const res = await fetch(URL + '/api/user?search=' + searchQuery, { + method: 'GET', + headers: { + Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, + }, + }) return res.json() } catch (error) { console.log(error) diff --git a/front-end/app/src/components/MyButton/style.js b/front-end/app/src/components/MyButton/style.js index 4630661b..004b8f87 100644 --- a/front-end/app/src/components/MyButton/style.js +++ b/front-end/app/src/components/MyButton/style.js @@ -13,6 +13,7 @@ export const styles = StyleSheet.create({ elevation: 10, shadowOpacity: 0.5, shadowRadius: 1, + alignSelf: 'center', }, text: { fontSize: 18, diff --git a/front-end/app/src/screens/setting-screens/UserAddScreen.js b/front-end/app/src/screens/setting-screens/UserAddScreen.js index 79d920b7..853a9f70 100644 --- a/front-end/app/src/screens/setting-screens/UserAddScreen.js +++ b/front-end/app/src/screens/setting-screens/UserAddScreen.js @@ -107,21 +107,21 @@ export function UserAddScreen() { + {DoDID && Rank && Name && AccountType && Position && ( + + addUserHandler({ + Rank, + Name, + DoDID, + Type: AccountType, + Position, + }) + } + /> + )} - {DoDID && Rank && Name && AccountType && Position && ( - - addUserHandler({ - Rank, - Name, - DoDID, - Type: AccountType, - Position, - }) - } - /> - )} ) } diff --git a/front-end/app/src/screens/setting-screens/UserMgtScreen.js b/front-end/app/src/screens/setting-screens/UserMgtScreen.js index 5d5368bf..8baa92fe 100644 --- a/front-end/app/src/screens/setting-screens/UserMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/UserMgtScreen.js @@ -1,35 +1,49 @@ -import React from 'react' -import { FAB, Avatar } from 'react-native-paper' -import { SafeAreaView, StyleSheet, ScrollView } from 'react-native' +import React, { useState, useEffect } from 'react' +import { FAB, Avatar, Colors } from 'react-native-paper' +//prettier-ignore +import { SafeAreaView, StyleSheet, TouchableOpacity, ScrollView, Text, View } from 'react-native' import { useNavigation } from '@react-navigation/native' +import searchUserApi from '../../apis/searchUserApi' +import { useNunitoFonts } from '../../hooks/useNunitoFonts' -const LeftImage = () => ( - +const Item = ({ Name, Rank, pic, Position }) => ( + + + {Rank} + {Name} + {Position} + + delete + + ) -const tempData = [ - { - title: '중위 이원빈', - description: '통신소대장', - }, - { - title: '중사 구창우', - description: '통신부소대장', - }, -] +export function UserMgtScreen() { + let [fontsLoaded] = useNunitoFonts() -const deleteUserHandler = () => {} + const [data, setData] = useState([]) + useEffect(() => { + const fetchUserHandler = async () => { + setData([...(await searchUserApi())]) + } + fetchUserHandler() + }, []) -export function UserMgtScreen() { const navigation = useNavigation() return ( + {data && + data.map((user, idx) => ( + + ))} Date: Sun, 16 Oct 2022 11:22:21 +0000 Subject: [PATCH 05/48] Feat: Add Unit Info Screen --- front-end/app/src/apis/addUnitApi.js | 21 ++++++++++ front-end/app/src/apis/fetchChatApi.js | 18 +++++++++ front-end/app/src/apis/updateUnitApi.js | 20 ++++++++++ front-end/app/src/apis/updateUserApi.js | 2 + .../app/src/components/ImagePicker/index.js | 11 ++++-- .../app/src/components/ImagePicker/style.js | 27 +++++++++++-- .../{ReportCard => ReportContent}/index.js | 6 +-- .../{ReportCard => ReportContent}/style.js | 16 ++++---- .../app/src/navigation/SettingNavigator.js | 6 +++ .../screens/chat-screens/ChatListScreen.js | 15 ++++--- front-end/app/src/screens/index.js | 1 + .../screens/report-screens/ReportScreen.js | 4 +- .../screens/setting-screens/SettingScreen.js | 3 +- .../screens/setting-screens/UnitMgtScreen.js | 32 ++++++++++++--- .../screens/setting-screens/UserMgtScreen.js | 2 +- .../setting-screens/UserUpdateScreen.js | 39 ++++++++++--------- 16 files changed, 172 insertions(+), 51 deletions(-) create mode 100644 front-end/app/src/apis/addUnitApi.js create mode 100644 front-end/app/src/apis/fetchChatApi.js create mode 100644 front-end/app/src/apis/updateUnitApi.js rename front-end/app/src/components/{ReportCard => ReportContent}/index.js (87%) rename front-end/app/src/components/{ReportCard => ReportContent}/style.js (84%) diff --git a/front-end/app/src/apis/addUnitApi.js b/front-end/app/src/apis/addUnitApi.js new file mode 100644 index 00000000..ac321ebe --- /dev/null +++ b/front-end/app/src/apis/addUnitApi.js @@ -0,0 +1,21 @@ +import URL from '../../url' +import asyncStorage from '@react-native-async-storage/async-storage' + +const addUnitApi = async ({ Unitname, Unitslogan, Logo }) => { + try { + console.log(URL + '/api/unit/add') + const res = await fetch(URL + '/api/unit/add', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, + }, + body: JSON.stringify({ Unitname, Unitslogan, Logo }), + }) + return res.json() + } catch (error) { + console.log(error) + } +} + +export default addUnitApi diff --git a/front-end/app/src/apis/fetchChatApi.js b/front-end/app/src/apis/fetchChatApi.js new file mode 100644 index 00000000..d62bfbb8 --- /dev/null +++ b/front-end/app/src/apis/fetchChatApi.js @@ -0,0 +1,18 @@ +import URL from '../../url' +import asyncStorage from '@react-native-async-storage/async-storage' + +const fetchChatApi = async () => { + try { + const res = await fetch(URL + '/api/chat', { + headers: { + Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, + }, + }) + console.log(res.status) + return res.json() + } catch (error) { + console.log(error) + } +} + +export default fetchChatApi diff --git a/front-end/app/src/apis/updateUnitApi.js b/front-end/app/src/apis/updateUnitApi.js new file mode 100644 index 00000000..d493a3e1 --- /dev/null +++ b/front-end/app/src/apis/updateUnitApi.js @@ -0,0 +1,20 @@ +import URL from '../../url' +import asyncStorage from '@react-native-async-storage/async-storage' + +const updateUnitApi = async ({ Unitname, Unitslogan, Logo }) => { + try { + const res = await fetch(URL + '/api/unit/add', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, + }, + body: JSON.stringify({ Unitname, Unitslogan, Logo }), + }) + return res.json() + } catch (error) { + console.log(error) + } +} + +export default updateUnitApi diff --git a/front-end/app/src/apis/updateUserApi.js b/front-end/app/src/apis/updateUserApi.js index be096d74..254dfceb 100644 --- a/front-end/app/src/apis/updateUserApi.js +++ b/front-end/app/src/apis/updateUserApi.js @@ -1,4 +1,5 @@ import URL from '../../url' +import asyncStorage from '@react-native-async-storage/async-storage' const updateUserApi = async ({ Rank, Name, email, milNumber, Number }) => { try { @@ -6,6 +7,7 @@ const updateUserApi = async ({ Rank, Name, email, milNumber, Number }) => { method: 'POST', headers: { 'Content-Type': 'application/json', + Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, }, body: JSON.stringify({ Rank, Name, email, milNumber, Number }), }) diff --git a/front-end/app/src/components/ImagePicker/index.js b/front-end/app/src/components/ImagePicker/index.js index eafd59ef..3d87ce34 100644 --- a/front-end/app/src/components/ImagePicker/index.js +++ b/front-end/app/src/components/ImagePicker/index.js @@ -1,10 +1,9 @@ import React, { useState } from 'react' import * as ExpoImagePicker from 'expo-image-picker' -import { Pressable, Image, Text } from 'react-native' +import { Pressable, Image, Text, View } from 'react-native' import { styles } from './style' -export function ImagePicker() { - const [imageUrl, setImageUrl] = useState('') +export function ImagePicker({ imageUrl, setImageUrl }) { const [status, requestPermission] = ExpoImagePicker.useMediaLibraryPermissions() @@ -32,7 +31,11 @@ export function ImagePicker() { return ( - 부대마크 변경하기 + {!imageUrl && ( + + {`부대 마크 변경하려면 클릭`} + + )} ) } diff --git a/front-end/app/src/components/ImagePicker/style.js b/front-end/app/src/components/ImagePicker/style.js index ee1ea790..fb35346a 100644 --- a/front-end/app/src/components/ImagePicker/style.js +++ b/front-end/app/src/components/ImagePicker/style.js @@ -1,11 +1,32 @@ import { StyleSheet } from 'react-native' +import { Colors } from 'react-native-paper' +import { window } from '../../constants/layout' export const styles = StyleSheet.create({ pressable: { - flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + marginBottom: window.height * 0.04, }, image: { - width: 150, - height: 150, + width: 0.8 * window.width, + height: 0.8 * window.width, + backgroundColor: Colors.grey300, + borderRadius: 5, + borderWidth: 2, + borderColor: Colors.grey500, + }, + absolute: { + position: 'absolute', + top: 0, + left: 0, + right: 0, + bottom: 0, + justifyContent: 'center', + alignItems: 'center', + }, + text: { + fontSize: 18, + color: Colors.grey700, }, }) diff --git a/front-end/app/src/components/ReportCard/index.js b/front-end/app/src/components/ReportContent/index.js similarity index 87% rename from front-end/app/src/components/ReportCard/index.js rename to front-end/app/src/components/ReportContent/index.js index 54f0b2e5..8655d00d 100644 --- a/front-end/app/src/components/ReportCard/index.js +++ b/front-end/app/src/components/ReportContent/index.js @@ -1,5 +1,5 @@ import { View, Text } from 'react-native' -import { Avatar, Paragraph, Button } from 'react-native-paper' +import { Paragraph, Button } from 'react-native-paper' import { useNunitoFonts } from '../../hooks/useNunitoFonts' import { Profile } from '../Profile' import { styles } from './style' @@ -7,7 +7,7 @@ import { styles } from './style' const text = '충성! 당직사령님, 사복을 입은 거수자가 나타났습니다.\n무기를 소지한 것 같지는 않고, 위병소 앞에서 두리번 거리고 있습니다.\n현재 경계 중이며, 특이사항 발생 시 보고드리겠습니다.' -export function ReportCard() { +export function ReportContent() { let [fontsLoaded] = useNunitoFonts() return ( @@ -23,7 +23,7 @@ export function ReportCard() { {`보고체계: 본부중대\n보고순서: 분대장 -> 소대장 -> 중대장`} + >{`체계: 본부중대\n순서: 분대장 -> 소대장 -> 중대장`} @@ -37,6 +37,7 @@ export function ReportContent({Content, Type}) { style={styles.upButton} color="white" onPress={() => console.log('pressed.')} + labelStyle={styles.ButtonLabel} > 상급보고 diff --git a/front-end/app/src/components/ReportContent/style.js b/front-end/app/src/components/ReportContent/style.js index d9a2c940..9ab7ebf4 100644 --- a/front-end/app/src/components/ReportContent/style.js +++ b/front-end/app/src/components/ReportContent/style.js @@ -3,12 +3,14 @@ import { Colors } from 'react-native-paper' export const styles = StyleSheet.create({ contentView: { - width: '95%', + width: '98%', alignItems: 'center', - borderBottomWidth: 1, + borderWidth: 1, + borderRadius: 10, borderColor: Colors.grey400, - paddingTop: 10, - paddingBottom: 10, + padding: 10, + backgroundColor: Colors.white, + marginBottom: 10, }, avatarView: { width: '100%', @@ -21,11 +23,16 @@ export const styles = StyleSheet.create({ fontFamily: 'NunitoSans_300Light', color: Colors.grey900, }, + flexRow: { + flexDirection: 'row', + }, paragraph: { width: '100%', marginTop: 5, fontFamily: 'NunitoSans_400Regular', fontSize: 13, + flex: 1, + flexWrap: 'wrap', }, contView: { width: '100%', @@ -38,7 +45,7 @@ export const styles = StyleSheet.create({ }, seqText: { marginTop: 5, - fontFamily: 'NunitoSans_SemiBold', + fontFamily: 'NunitoSans_600SemiBold', fontSize: 11, color: Colors.grey800, }, @@ -52,12 +59,16 @@ export const styles = StyleSheet.create({ }, endButton: { backgroundColor: Colors.green600, - borderRadius: 8, + borderRadius: 5, marginRight: 5, + }, + ButtonLabel: { fontSize: 13, + fontFamily: 'NunitoSans_700Bold', }, upButton: { backgroundColor: Colors.red600, - borderRadius: 8, + borderRadius: 5, + fontFamily: 'NunitoSans_600SemiBold', }, }) diff --git a/front-end/app/src/components/ReportHeader/index.js b/front-end/app/src/components/ReportHeader/index.js index 53f0f8ee..7c522f3d 100644 --- a/front-end/app/src/components/ReportHeader/index.js +++ b/front-end/app/src/components/ReportHeader/index.js @@ -1,24 +1,38 @@ -import { View } from 'react-native' -import { Text } from 'react-native-paper' +import { View, TouchableOpacity } from 'react-native' +import { Text, Colors, Avatar } from 'react-native-paper' import { styles } from './style' import { useNunitoFonts } from '../../hooks/useNunitoFonts' -import moment from 'moment' +import { useNavigation } from '@react-navigation/native' export function ReportHeader({ Title, isEnd, severity, date }) { let [fontsLoaded] = useNunitoFonts() + const navigation = useNavigation() return ( + navigation.goBack()}> + + - 3초소 거수자 발견 - {'[미종결]'} + {Title} + + {isEnd ? '[종결]' : '[미종결]'} + 중요도: - {3} - - {moment().subtract(6, 'days').format('YYYY-MM-DD hh:mm')} - + {severity} + {date} ) diff --git a/front-end/app/src/components/ReportHeader/style.js b/front-end/app/src/components/ReportHeader/style.js index b9c63963..5fba5f37 100644 --- a/front-end/app/src/components/ReportHeader/style.js +++ b/front-end/app/src/components/ReportHeader/style.js @@ -4,32 +4,39 @@ import { Colors } from 'react-native-paper' export const styles = StyleSheet.create({ header: { width: '95%', - borderBottomWidth: 1, - borderBottomColor: Colors.grey400, - }, - title: { - fontSize: 20, - fontFamily: 'NunitoSans_600SemiBold', }, titleView: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', + marginTop: 10, }, - text: { - fontSize: 18, + left: { + backgroundColor: Colors.white, + position: 'absolute', + left: -15, + padding: 10, + }, + title: { + fontSize: 20, + fontFamily: 'NunitoSans_300Light', + }, + isEnd: { + fontSize: 19, marginLeft: 5, - color: 'red', fontFamily: 'NunitoSans_600SemiBold', }, - severity: { color: 'red', fontFamily: 'NunitoSans_600SemiBold' }, + severity: { + fontSize: 13, + color: Colors.red600, + fontFamily: 'NunitoSans_600SemiBold', + }, subView: { width: '100%', flexDirection: 'row', justifyContent: 'flex-end', - marginTop: 5, + marginVertical: 5, marginRight: 15, - marginBottom: 5, }, severityText: { fontSize: 13, @@ -37,9 +44,8 @@ export const styles = StyleSheet.create({ marginRight: 3, }, dateText: { - fontSize: 13, + fontSize: 12, fontFamily: 'NunitoSans_300Light', - marginLeft: 10, - marginRight: 10, + marginHorizontal: 10, }, }) diff --git a/front-end/app/src/components/ReportListItem/index.js b/front-end/app/src/components/ReportListItem/index.js index 781ff891..0b0ed24b 100644 --- a/front-end/app/src/components/ReportListItem/index.js +++ b/front-end/app/src/components/ReportListItem/index.js @@ -1,13 +1,15 @@ import React from 'react' import { TouchableOpacity, Text, View } from 'react-native' -import { Card, Title, Paragraph } from 'react-native-paper' +import { Card, Paragraph, Colors } from 'react-native-paper' import { useNunitoFonts } from '../../hooks/useNunitoFonts' import { useNavigation } from '@react-navigation/native' -import moment from 'moment' import { styles } from './style' // prettier-ignore -export function ReportListItem({ Title, isEnd, Content, severity, date, Type }) { +export function ReportListItem(props) { + const { Title, isEnd, Content, severity, date, Type } = props + console.log(props) + let [fontsLoaded] = useNunitoFonts() const navigation = useNavigation() @@ -24,38 +26,28 @@ export function ReportListItem({ Title, isEnd, Content, severity, date, Type }) } return ( - - + - 3초소 거수자 발견 - {'[미종결]'} + {Title} + {isEnd ? '[종결]' : '[미종결]'} - 충성! 당직사령님. 3초소에 사복을 입은 거수자가 나타났습니다. 무기를 - 소지한 것 같지는 않고 위병소 앞에서 두리번 거리고 있습니다. 현재 - 경계중이며, 추가사항 발생시 보고드리겠습니다. + {Content} - 중요도: - - {3} - - - {moment().subtract(6, 'days').format('YYYY-MM-DD hh:mm')} + 중요도: + {severity} + + {date} - ) } diff --git a/front-end/app/src/components/ReportListItem/style.js b/front-end/app/src/components/ReportListItem/style.js index c720f123..a10c7aa4 100644 --- a/front-end/app/src/components/ReportListItem/style.js +++ b/front-end/app/src/components/ReportListItem/style.js @@ -3,22 +3,24 @@ import { Colors } from 'react-native-paper' export const styles = StyleSheet.create({ cardListItem: { - width: '97%', - borderColor: Colors.grey400, + width: '96%', backgroundColor: 'white', - marginHorizontal: 10, marginTop: 8, - borderRadius: 5, + borderRadius: 12, paddingVertical: 3, + borderWidth: 1, }, title: { - fontSize: 17, + fontSize: 18, fontFamily: 'NunitoSans_600SemiBold', + paddingVertical: 4, }, paragraph: { - fontSize: 14, + fontSize: 13, fontFamily: 'NunitoSans_400Regular', - color: Colors.grey700, + color: Colors.grey800, + flex: 1, + flexWrap: 'wrap', }, flexRow: { flexDirection: 'row', @@ -29,14 +31,24 @@ export const styles = StyleSheet.create({ justifyContent: 'flex-end', marginTop: 5, }, - text: { - fontSize: 15, - marginLeft: 3, - color: 'red', + isEnd: { + fontSize: 17, + marginLeft: 5, fontFamily: 'NunitoSans_600SemiBold', }, - footer: { + severityText: { + fontSize: 13, + fontFamily: 'NunitoSans_300Light', + marginRight: 3, + }, + severity: { fontSize: 13, + fontFamily: 'NunitoSans_600SemiBold', + color: 'red', + }, + date: { + fontSize: 12, fontFamily: 'NunitoSans_300Light', + marginLeft: 10, }, }) diff --git a/front-end/app/src/navigation/ReportNavigator.js b/front-end/app/src/navigation/ReportNavigator.js index 8b2af28c..e492efe5 100644 --- a/front-end/app/src/navigation/ReportNavigator.js +++ b/front-end/app/src/navigation/ReportNavigator.js @@ -1,12 +1,15 @@ import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs' import { RecdReportNavigator } from './RecdReportNavigator' import { SentReportNavigator } from './SentReportNavigator' +import { Colors } from 'react-native-paper' const Tab = createMaterialTopTabNavigator() export function ReportNavigator() { return ( - + { if (route.state) { - return getActiveRouteName(route.state.routes[route.state.index]); + return getActiveRouteName(route.state.routes[route.state.index]) } - return route.name; -}; + return route.name +} const screenOptions = ({ route }) => { return { tabBarIcon: ({ focused, size }) => { - const { name } = route; - const focusedSize = focused ? size + 6 : size; - const focusedColor = focused ? Colors.white : Colors.grey400; - const [icon, iconOutline] = icons[name]; - const iconName = focused ? icon : iconOutline; - return ; + const { name } = route + const focusedSize = focused ? size + 6 : size + const focusedColor = focused ? Colors.white : Colors.grey400 + const [icon, iconOutline] = icons[name] + const iconName = focused ? icon : iconOutline + return }, tabBarShowLabel: true, - headerTitleAlign: "center", - tabBarStyle: { height: 55, paddingBottom: 5, backgroundColor: "#008272" }, + headerTitleAlign: 'center', + tabBarStyle: { height: 55, paddingBottom: 5, backgroundColor: '#008272' }, tabBarLabelStyle: { color: Colors.grey200 }, - }; -}; + } +} export function TabNavigator() { return ( - ); + ) } diff --git a/front-end/app/src/screens/LoginScreen/index.js b/front-end/app/src/screens/LoginScreen/index.js index 45a22063..2f97d9a3 100644 --- a/front-end/app/src/screens/LoginScreen/index.js +++ b/front-end/app/src/screens/LoginScreen/index.js @@ -28,9 +28,8 @@ export function LoginScreen() { ...res, token: null, }) - cb() - console.log(res) - console.log(userMe) + Alert.alert(`${userMe.Name}님, 환영합니다.`) + cb() } else { Alert.alert(res.message) } diff --git a/front-end/app/src/screens/report-screens/RecdReportScreen.js b/front-end/app/src/screens/report-screens/RecdReportScreen.js index a13186b4..8aa319fa 100644 --- a/front-end/app/src/screens/report-screens/RecdReportScreen.js +++ b/front-end/app/src/screens/report-screens/RecdReportScreen.js @@ -1,11 +1,21 @@ -import React, { useState } from 'react' +import React from 'react' import { ReportListItem } from '../../components/ReportListItem' // prettier-ignore import { SafeAreaView, StyleSheet, ScrollView } from 'react-native' import { Colors, FAB } from 'react-native-paper' import { useNavigation } from '@react-navigation/native' +import moment from 'moment' import fetchReportApi from '../../apis/fetchReportApi' +const { Title, isEnd, Content, severity, date, Type } = { + Title: '3초소 거수자 발견', + isEnd: false, + Content: `충성! 당직사령님, 3초소에 사복을 입은 거수자가 나타났습니다.\n무기는 소지하고 있지 않은 것으로 보이며, 위병소 앞에서 두리번 거리고 있습니다.\n현재 경계중이며, 추가사항 발생시 보고드리겠습니다.`, + severity: 3, + date: `${moment().subtract(6, 'days').format('YYYY-MM-DD hh:mm')}`, + Type: '긴급상황', +} + export function RecdReportScreen() { const navigation = useNavigation() // const [reports, setReports] = useState(() => fetchReportHandler()) @@ -16,31 +26,28 @@ export function RecdReportScreen() { contentContainerStyle={styles.scrollView} showsVerticalScrollIndicator={false} > - - - - - - - - - - {/* {reports && - reports.map((report, idx) => ( - - ))} */} + + navigation.navigate('CreateReportScreen')} style={styles.fab} + color="white" /> ) @@ -49,8 +56,8 @@ export function RecdReportScreen() { const styles = StyleSheet.create({ container: { flex: 1, - backgroundColor: Colors.grey200, - marginBottom: 10, + backgroundColor: Colors.white, + paddingBottom: 10, }, scrollView: { width: '100%', @@ -67,5 +74,6 @@ const styles = StyleSheet.create({ position: 'absolute', bottom: 15, right: 20, + backgroundColor: Colors.green500, }, }) diff --git a/front-end/app/src/screens/report-screens/ReportScreen.js b/front-end/app/src/screens/report-screens/ReportScreen.js index f59ac6e3..674e0119 100644 --- a/front-end/app/src/screens/report-screens/ReportScreen.js +++ b/front-end/app/src/screens/report-screens/ReportScreen.js @@ -1,5 +1,5 @@ import React, { useState } from 'react' -import { SafeAreaView, StyleSheet, View, Text, FlatList } from 'react-native' +import { SafeAreaView, StyleSheet, View, FlatList, Text } from 'react-native' import { TextInput } from 'react-native-paper' import { ReportHeader } from '../../components/ReportHeader' import { ReportContent } from '../../components/ReportContent' @@ -30,15 +30,26 @@ export function ReportScreen({ route }) { date={date} /> + + + Comments. + + ) const renderItem = ({ item }) => { return ( ) } @@ -50,34 +61,35 @@ export function ReportScreen({ route }) { data={comments} renderItem={renderItem} /> - - setComment(text)} - value={comment} - right={ - { - setComments([ - ...comments, - { - name: userMe.Name, - position: userMe.Position, - text: comment, - }, - ]) - addCommentHandler({ Title, Type, Content: comment }) - }} - /> - } - > - + setComment(text)} + value={comment} + right={ + { + setComments([ + ...comments, + { + Name: userMe.Name, + position: userMe.Position, + Content: comment, + }, + ]) + addCommentHandler({ Title, Type, Content: comment }) + setComment('') + }} + /> + } + > ) } @@ -85,18 +97,19 @@ export function ReportScreen({ route }) { const styles = StyleSheet.create({ container: { flex: 1, - backgroundColor: 'white', + backgroundColor: Colors.white, alignItems: 'center', + paddingBottom: 40, }, - commentInputView: { + + commentInput: { bottom: 0, position: 'absolute', - flexDirection: 'row', + paddingTop: 5, width: '100%', - alignItems: 'center', backgroundColor: 'white', - }, - commentInput: { - width: '100%', + borderWidth: 2, + borderColor: Colors.grey400, + borderBottomWidth: 0, }, }) From 4c76498983ec24dc131b6516a9d9b2d0caae0428 Mon Sep 17 00:00:00 2001 From: hyeongmin Kim <113012760+gudmin0526@users.noreply.github.com> Date: Mon, 17 Oct 2022 12:52:47 +0000 Subject: [PATCH 09/48] Refactor: refactor navigation structure --- front-end/app/src/components/Profile/index.js | 4 +- .../app/src/components/ReportComment/style.js | 7 +- .../app/src/components/ReportContent/index.js | 2 +- .../app/src/components/ReportContent/style.js | 7 +- .../app/src/components/ReportGroup/index.js | 2 +- .../app/src/components/ReportGroup/style.js | 16 +- .../app/src/components/ReportHeader/index.js | 15 +- .../app/src/components/ReportHeader/style.js | 2 - .../src/components/ReportListItem/style.js | 5 +- front-end/app/src/navigation/ChatNavigator.js | 21 --- front-end/app/src/navigation/MainNavigator.js | 78 ++++++-- .../app/src/navigation/RecdReportNavigator.js | 17 -- .../app/src/navigation/ReportNavigator.js | 12 +- .../app/src/navigation/SentReportNavigator.js | 15 -- .../app/src/navigation/SettingNavigator.js | 49 ----- front-end/app/src/navigation/TabNavigator.js | 19 +- .../app/src/screens/LoginScreen/index.js | 8 +- .../app/src/screens/SignUpScreen/index.js | 12 +- .../report-screens/CreateReportScreen.js | 177 ++++++++---------- .../report-screens/RecdReportScreen.js | 6 +- .../screens/report-screens/ReportScreen.js | 83 ++++---- 21 files changed, 238 insertions(+), 319 deletions(-) delete mode 100644 front-end/app/src/navigation/ChatNavigator.js delete mode 100644 front-end/app/src/navigation/RecdReportNavigator.js delete mode 100644 front-end/app/src/navigation/SentReportNavigator.js delete mode 100644 front-end/app/src/navigation/SettingNavigator.js diff --git a/front-end/app/src/components/Profile/index.js b/front-end/app/src/components/Profile/index.js index 1887ae68..0a0778d7 100644 --- a/front-end/app/src/components/Profile/index.js +++ b/front-end/app/src/components/Profile/index.js @@ -9,7 +9,7 @@ export function Profile({ size = 45, src = require('../../assets/images/avatar.png'), date, - right + right, }) { let [fontsLoaded] = useNunitoFonts() @@ -25,7 +25,7 @@ export function Profile({ {date} )} - {right && (right)} + {right && right} ) } diff --git a/front-end/app/src/components/ReportComment/style.js b/front-end/app/src/components/ReportComment/style.js index 915045b5..3b5eae03 100644 --- a/front-end/app/src/components/ReportComment/style.js +++ b/front-end/app/src/components/ReportComment/style.js @@ -1,21 +1,20 @@ import { StyleSheet } from 'react-native' import { Colors } from 'react-native-paper' -import { window } from '../../constants/layout' export const styles = StyleSheet.create({ contentView: { - width: '95%', + width: '97%', borderBottomWidth: 1, borderColor: Colors.grey400, paddingVertical: 8, - marginLeft: window.width * 0.025, paddingLeft: 3, + alignSelf: 'center', }, avatarView: { width: '100%', flexDirection: 'row', }, - nameView: { marginLeft: 6, marginTop: 4 }, + nameView: { marginTop: 4 }, name: { fontSize: 14, fontFamily: 'NunitoSans_700Bold' }, position: { fontSize: 11, diff --git a/front-end/app/src/components/ReportContent/index.js b/front-end/app/src/components/ReportContent/index.js index d6cbb5bc..b8b30eb8 100644 --- a/front-end/app/src/components/ReportContent/index.js +++ b/front-end/app/src/components/ReportContent/index.js @@ -12,7 +12,7 @@ export function ReportContent({ Content, Type }) { diff --git a/front-end/app/src/components/ReportContent/style.js b/front-end/app/src/components/ReportContent/style.js index 9ab7ebf4..c6dbd205 100644 --- a/front-end/app/src/components/ReportContent/style.js +++ b/front-end/app/src/components/ReportContent/style.js @@ -5,8 +5,8 @@ export const styles = StyleSheet.create({ contentView: { width: '98%', alignItems: 'center', - borderWidth: 1, - borderRadius: 10, + borderWidth: 1.5, + borderRadius: 5, borderColor: Colors.grey400, padding: 10, backgroundColor: Colors.white, @@ -61,6 +61,7 @@ export const styles = StyleSheet.create({ backgroundColor: Colors.green600, borderRadius: 5, marginRight: 5, + elevation: 3, }, ButtonLabel: { fontSize: 13, @@ -69,6 +70,6 @@ export const styles = StyleSheet.create({ upButton: { backgroundColor: Colors.red600, borderRadius: 5, - fontFamily: 'NunitoSans_600SemiBold', + elevation: 3, }, }) diff --git a/front-end/app/src/components/ReportGroup/index.js b/front-end/app/src/components/ReportGroup/index.js index 8b1e76db..aabb5d97 100644 --- a/front-end/app/src/components/ReportGroup/index.js +++ b/front-end/app/src/components/ReportGroup/index.js @@ -8,7 +8,7 @@ const ItemSeparator = () => ( ) diff --git a/front-end/app/src/components/ReportGroup/style.js b/front-end/app/src/components/ReportGroup/style.js index aff004a0..197bdd7b 100644 --- a/front-end/app/src/components/ReportGroup/style.js +++ b/front-end/app/src/components/ReportGroup/style.js @@ -7,12 +7,12 @@ export const styles = StyleSheet.create({ }, view: { borderWidth: 1, - borderRadius: 2, - borderColor: Colors.grey800, + borderRadius: 6, + borderColor: Colors.grey700, alignItems: 'center', - paddingVertical: 4, - width: 70, - marginVertical: 5, + paddingVertical: 3, + width: 75, + marginBottom: 2, }, image: { marginBottom: 5, @@ -20,12 +20,12 @@ export const styles = StyleSheet.create({ itemText: { fontFamily: 'NunitoSans_400Regular', fontSize: 12, - marginBottom: 5, }, text: { fontFamily: 'NunitoSans_300Light', - color: Colors.grey600, + color: Colors.grey700, fontSize: 13, - marginBottom: 14, + paddingTop: 1, + marginBottom: 10, }, }) diff --git a/front-end/app/src/components/ReportHeader/index.js b/front-end/app/src/components/ReportHeader/index.js index 7c522f3d..ea56b823 100644 --- a/front-end/app/src/components/ReportHeader/index.js +++ b/front-end/app/src/components/ReportHeader/index.js @@ -1,23 +1,12 @@ -import { View, TouchableOpacity } from 'react-native' -import { Text, Colors, Avatar } from 'react-native-paper' +import { View } from 'react-native' +import { Text, Colors } from 'react-native-paper' import { styles } from './style' import { useNunitoFonts } from '../../hooks/useNunitoFonts' -import { useNavigation } from '@react-navigation/native' export function ReportHeader({ Title, isEnd, severity, date }) { let [fontsLoaded] = useNunitoFonts() - const navigation = useNavigation() - return ( - navigation.goBack()}> - - {Title} - - - - ) -} diff --git a/front-end/app/src/navigation/MainNavigator.js b/front-end/app/src/navigation/MainNavigator.js index 86aed4c8..8c0d46bd 100644 --- a/front-end/app/src/navigation/MainNavigator.js +++ b/front-end/app/src/navigation/MainNavigator.js @@ -2,24 +2,80 @@ import React from 'react' import { createStackNavigator } from '@react-navigation/stack' import { LoginScreen } from '../screens/LoginScreen' import { SignUpScreen } from '../screens/SignUpScreen' -import { ChatNavigator } from './ChatNavigator' +import { TabNavigator } from './TabNavigator' +import { + ReportScreen, + CreateReportScreen, + ChatRoomScreen, + UserUpdateScreen, + UserAddScreen, + UserMgtScreen, + UnitMgtScreen, + ProcMgtScreen, +} from '../screens' const Stack = createStackNavigator() -export default function MainNavigator() { +export default function MainNavigator({ route }) { return ( - - - + + - + + + + + + + + + ) } diff --git a/front-end/app/src/navigation/RecdReportNavigator.js b/front-end/app/src/navigation/RecdReportNavigator.js deleted file mode 100644 index 0ee7e417..00000000 --- a/front-end/app/src/navigation/RecdReportNavigator.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react' -import { createStackNavigator } from '@react-navigation/stack' -import { RecdReportScreen } from '../screens' -import { ReportScreen } from '../screens' -import { CreateReportScreen } from '../screens' - -const Stack = createStackNavigator() - -export function RecdReportNavigator() { - return ( - - - - - - ) -} diff --git a/front-end/app/src/navigation/ReportNavigator.js b/front-end/app/src/navigation/ReportNavigator.js index e492efe5..7f9c364b 100644 --- a/front-end/app/src/navigation/ReportNavigator.js +++ b/front-end/app/src/navigation/ReportNavigator.js @@ -1,7 +1,7 @@ import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs' -import { RecdReportNavigator } from './RecdReportNavigator' -import { SentReportNavigator } from './SentReportNavigator' + import { Colors } from 'react-native-paper' +import { RecdReportScreen, SentReportScreen } from '../screens' const Tab = createMaterialTopTabNavigator() @@ -11,16 +11,16 @@ export function ReportNavigator() { tabBarOptions={{ indicatorStyle: { backgroundColor: Colors.green800 } }} > - - - - ) -} diff --git a/front-end/app/src/navigation/SettingNavigator.js b/front-end/app/src/navigation/SettingNavigator.js deleted file mode 100644 index e72eae1d..00000000 --- a/front-end/app/src/navigation/SettingNavigator.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react' -import { createStackNavigator } from '@react-navigation/stack' -import { - SettingScreen, - UnitMgtScreen, - UserMgtScreen, - UserAddScreen, - ProcMgtScreen, - UserUpdateScreen, -} from '../screens' - -const Stack = createStackNavigator() - -export function SettingNavigator() { - return ( - - - - - - - - - ) -} diff --git a/front-end/app/src/navigation/TabNavigator.js b/front-end/app/src/navigation/TabNavigator.js index 51361733..a418ade4 100644 --- a/front-end/app/src/navigation/TabNavigator.js +++ b/front-end/app/src/navigation/TabNavigator.js @@ -3,8 +3,7 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' import { Colors } from 'react-native-paper' import Icon from 'react-native-vector-icons/MaterialCommunityIcons' import { ReportNavigator } from './ReportNavigator' -import { SettingNavigator } from './SettingNavigator' -import { ChatListScreen, OrgChartScreen } from '../screens' +import { ChatListScreen, OrgChartScreen, SettingScreen } from '../screens' const Tab = createBottomTabNavigator() @@ -12,15 +11,7 @@ const icons = { ReportNavigator: ['note-text', 'note-text-outline'], ChatListScreen: ['message-text', 'message-text-outline'], OrgChartScreen: ['graph', 'graph-outline'], - SettingNavigator: ['cog', 'cog-outline'], -} - -const getActiveRouteName = (route) => { - if (route.state) { - return getActiveRouteName(route.state.routes[route.state.index]) - } - - return route.name + SettingScreen: ['cog', 'cog-outline'], } const screenOptions = ({ route }) => { @@ -62,9 +53,9 @@ export function TabNavigator() { component={OrgChartScreen} /> ) diff --git a/front-end/app/src/screens/LoginScreen/index.js b/front-end/app/src/screens/LoginScreen/index.js index 2f97d9a3..ce0f4613 100644 --- a/front-end/app/src/screens/LoginScreen/index.js +++ b/front-end/app/src/screens/LoginScreen/index.js @@ -29,7 +29,7 @@ export function LoginScreen() { token: null, }) Alert.alert(`${userMe.Name}님, 환영합니다.`) - cb() + cb() } else { Alert.alert(res.message) } @@ -42,8 +42,8 @@ export function LoginScreen() { const navigation = useNavigation() - const goChatNavigator = useCallback( - () => navigation.navigate('ChatNavigator'), + const goTabNavigator = useCallback( + () => navigation.navigate('TabNavigator'), [] ) const goSignUpScreen = useCallback( @@ -92,7 +92,7 @@ export function LoginScreen() { loginHandler({ DoDID, password }, goChatNavigator)} + onPress={() => loginHandler({ DoDID, password }, goTabNavigator)} style={styles.loginButtonView} > 로 그 인 diff --git a/front-end/app/src/screens/SignUpScreen/index.js b/front-end/app/src/screens/SignUpScreen/index.js index 4422cbdd..76d24d28 100644 --- a/front-end/app/src/screens/SignUpScreen/index.js +++ b/front-end/app/src/screens/SignUpScreen/index.js @@ -73,7 +73,7 @@ export function SignUpScreen() { activeUnderlineColor="#008275" onChangeText={(Name) => setName(Name)} style={styles.signUpTextInput} - > + /> @@ -83,7 +83,7 @@ export function SignUpScreen() { activeUnderlineColor="#008275" onChangeText={(DoDID) => setDoDID(DoDID)} style={styles.signUpTextInput} - > + /> @@ -93,7 +93,7 @@ export function SignUpScreen() { activeUnderlineColor="#008275" onChangeText={(password) => setPassword(password)} style={styles.signUpTextInput} - > + /> @@ -105,7 +105,7 @@ export function SignUpScreen() { setConfirmPassword(confirmPassword) } style={styles.signUpTextInput} - > + /> setEmail(email)} style={styles.signUpTextInput} - > + /> @@ -127,7 +127,7 @@ export function SignUpScreen() { activeUnderlineColor="#008275" onChangeText={(Invcode) => setInvcode(Invcode)} style={styles.signUpTextInput} - > + /> diff --git a/front-end/app/src/screens/report-screens/CreateReportScreen.js b/front-end/app/src/screens/report-screens/CreateReportScreen.js index b3232165..4234ed2a 100644 --- a/front-end/app/src/screens/report-screens/CreateReportScreen.js +++ b/front-end/app/src/screens/report-screens/CreateReportScreen.js @@ -1,7 +1,7 @@ import React, { useState } from 'react' // prettier-ignore -import { TextInput, SafeAreaView, View, StyleSheet, ScrollView } from 'react-native' -import { Colors, Searchbar, Text, Avatar } from 'react-native-paper' +import { SafeAreaView, View, StyleSheet, ScrollView } from 'react-native' +import { Colors, Searchbar, Text, Avatar, TextInput } from 'react-native-paper' import { useNunitoFonts } from '../../hooks/useNunitoFonts' import DropDownPicker from 'react-native-dropdown-picker' import { ReportGroup } from '../../components/ReportGroup' @@ -10,6 +10,7 @@ import { useNavigation } from '@react-navigation/native' import { Profile } from '../../components/Profile' import searchUserApi from '../../apis/searchUserApi' import DATA from '../../data/procData' +import { window } from '../../constants/layout' const rightIcon = ({ key, addedUser, setAddedUser }) => ( ( export function CreateReportScreen() { const fetchUserHandler = async (query) => { const res = await searchUserApi(query) + console.log(res) return res } @@ -35,6 +37,8 @@ export function CreateReportScreen() { const [query, setQuery] = useState('') const [addedUser, setAddedUser] = useState([]) + console.log(addedUser) + const [typeOpen, setTypeOpen] = useState(false) const [type, setType] = useState('') const [typeItem, setTypeItem] = useState([ @@ -56,20 +60,19 @@ export function CreateReportScreen() { return ( - - 제목 - setTitle(title)} - value={title} - > - - - 보고종류 + setTitle(title)} + value={title} + activeUnderlineColor="#008275" + > + - - - 보고체계 - - 보고된 인원 + {groups.includes('onDuty') && ( )} @@ -106,48 +115,43 @@ export function CreateReportScreen() { )} - - 추가된 인원 - setQuery(query)} - onSubmitEditing={() => - setAddedUser([...addedUser, fetchUserHandler(query)]) - } - onIconPress={() => - setAddedUser([...addedUser, fetchUserHandler(query)]) - } - /> - - {addedUser.map((user, idx) => ( - - } - /> - ))} - - - - 내용 - setText(text)} - value={text} - > - + setQuery(query)} + onSubmitEditing={() => + setAddedUser([...addedUser, fetchUserHandler(query)]) + } + onIconPress={() => + setAddedUser([...addedUser, fetchUserHandler(query)]) + } + activeUnderlineColor="#008275" + /> + + {addedUser.map((user, idx) => ( + + ))} + + setText(text)} + value={text} + activeUnderlineColor="#008275" + > {type && groups && text && ( @@ -60,36 +60,40 @@ export function ReportScreen({ route }) { ListHeaderComponent={ListHeaderComponent} data={comments} renderItem={renderItem} + showsVerticalScrollIndicator={false} /> - setComment(text)} - value={comment} - right={ - { - setComments([ - ...comments, - { - Name: userMe.Name, - position: userMe.Position, - Content: comment, - }, - ]) - addCommentHandler({ Title, Type, Content: comment }) - setComment('') - }} - /> - } - > + + + setComment(text)} + value={comment} + right={ + { + setComments([ + ...comments, + { + Name: userMe.Name, + position: userMe.Position, + Content: comment, + }, + ]) + addCommentHandler({ Title, Type, Content: comment }) + setComment('') + }} + /> + } + > + ) } @@ -99,17 +103,18 @@ const styles = StyleSheet.create({ flex: 1, backgroundColor: Colors.white, alignItems: 'center', - paddingBottom: 40, + paddingBottom: 50, }, - - commentInput: { + view: { bottom: 0, position: 'absolute', - paddingTop: 5, width: '100%', - backgroundColor: 'white', - borderWidth: 2, - borderColor: Colors.grey400, - borderBottomWidth: 0, + alignItems: 'center', + }, + commentInput: { + paddingTop: 5, + width: '96%', + backgroundColor: Colors.grey100, + elevation: 4, }, }) From 1475b4c1e10649ebecea1f41244eb688db971a21 Mon Sep 17 00:00:00 2001 From: hyeongmin Kim <113012760+gudmin0526@users.noreply.github.com> Date: Mon, 17 Oct 2022 13:52:04 +0000 Subject: [PATCH 10/48] Refactor: refactor Navigator --- front-end/app/src/apis/addUnitApi.js | 2 +- front-end/app/src/apis/updateUnitApi.js | 6 +- front-end/app/src/apis/updateUnitLogoApi.js | 20 +++++ front-end/app/src/apis/updateUserApi.js | 4 +- front-end/app/src/apis/updateUserPic.js | 20 +++++ front-end/app/src/navigation/ChatNavigator.js | 17 ++++ front-end/app/src/navigation/MainNavigator.js | 77 +++---------------- .../app/src/navigation/ReportNavigator.js | 39 ++++------ .../app/src/navigation/SettingNavigator.js | 49 ++++++++++++ front-end/app/src/navigation/TabNavigator.js | 10 +-- front-end/app/src/navigation/TopNavigator.js | 30 ++++++++ front-end/app/src/screens/index.js | 3 +- .../screens/setting-screens/SettingScreen.js | 6 ++ .../{ProcMgtScreen.js => SysMgtScreen.js} | 2 +- .../screens/setting-screens/UnitAddScreen.js | 66 ++++++++++++++++ .../screens/setting-screens/UnitMgtScreen.js | 24 ++++-- .../setting-screens/UserUpdateScreen.js | 14 +++- 17 files changed, 278 insertions(+), 111 deletions(-) create mode 100644 front-end/app/src/apis/updateUnitLogoApi.js create mode 100644 front-end/app/src/apis/updateUserPic.js create mode 100644 front-end/app/src/navigation/ChatNavigator.js create mode 100644 front-end/app/src/navigation/SettingNavigator.js create mode 100644 front-end/app/src/navigation/TopNavigator.js rename front-end/app/src/screens/setting-screens/{ProcMgtScreen.js => SysMgtScreen.js} (90%) create mode 100644 front-end/app/src/screens/setting-screens/UnitAddScreen.js diff --git a/front-end/app/src/apis/addUnitApi.js b/front-end/app/src/apis/addUnitApi.js index ac321ebe..4860608f 100644 --- a/front-end/app/src/apis/addUnitApi.js +++ b/front-end/app/src/apis/addUnitApi.js @@ -3,7 +3,7 @@ import asyncStorage from '@react-native-async-storage/async-storage' const addUnitApi = async ({ Unitname, Unitslogan, Logo }) => { try { - console.log(URL + '/api/unit/add') + console.log(URL + '/api/unit') const res = await fetch(URL + '/api/unit/add', { method: 'POST', headers: { diff --git a/front-end/app/src/apis/updateUnitApi.js b/front-end/app/src/apis/updateUnitApi.js index d493a3e1..7b389577 100644 --- a/front-end/app/src/apis/updateUnitApi.js +++ b/front-end/app/src/apis/updateUnitApi.js @@ -1,15 +1,15 @@ import URL from '../../url' import asyncStorage from '@react-native-async-storage/async-storage' -const updateUnitApi = async ({ Unitname, Unitslogan, Logo }) => { +const updateUnitApi = async ({ Unitname, Unitslogan }) => { try { - const res = await fetch(URL + '/api/unit/add', { + const res = await fetch(URL + '/api/unit/', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, }, - body: JSON.stringify({ Unitname, Unitslogan, Logo }), + body: JSON.stringify({ Unitname, Unitslogan }), }) return res.json() } catch (error) { diff --git a/front-end/app/src/apis/updateUnitLogoApi.js b/front-end/app/src/apis/updateUnitLogoApi.js new file mode 100644 index 00000000..8d79c5eb --- /dev/null +++ b/front-end/app/src/apis/updateUnitLogoApi.js @@ -0,0 +1,20 @@ +import URL from '../../url' +import asyncStorage from '@react-native-async-storage/async-storage' + +const updateUnitLogoApi = async ({ Logo }) => { + try { + const res = await fetch(URL + '/api/unit/logo', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, + }, + body: JSON.stringify({ Logo }), + }) + return res.json() + } catch (error) { + console.log(error) + } +} + +export default updateUnitLogoApi diff --git a/front-end/app/src/apis/updateUserApi.js b/front-end/app/src/apis/updateUserApi.js index 254dfceb..4b3232b1 100644 --- a/front-end/app/src/apis/updateUserApi.js +++ b/front-end/app/src/apis/updateUserApi.js @@ -3,8 +3,8 @@ import asyncStorage from '@react-native-async-storage/async-storage' const updateUserApi = async ({ Rank, Name, email, milNumber, Number }) => { try { - const res = await fetch(URL + '/api/user/update', { - method: 'POST', + const res = await fetch(URL + '/api/user', { + method: 'PUT', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, diff --git a/front-end/app/src/apis/updateUserPic.js b/front-end/app/src/apis/updateUserPic.js new file mode 100644 index 00000000..2bfbe5ad --- /dev/null +++ b/front-end/app/src/apis/updateUserPic.js @@ -0,0 +1,20 @@ +import URL from '../../url' +import asyncStorage from '@react-native-async-storage/async-storage' + +const updateUserPicApi = async ({ pic }) => { + try { + const res = await fetch(URL + '/api/user/pic', { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, + }, + body: JSON.stringify({ pic }), + }) + return res.json() + } catch (error) { + console.log(error) + } +} + +export default updateUserPicApi diff --git a/front-end/app/src/navigation/ChatNavigator.js b/front-end/app/src/navigation/ChatNavigator.js new file mode 100644 index 00000000..4d20b31c --- /dev/null +++ b/front-end/app/src/navigation/ChatNavigator.js @@ -0,0 +1,17 @@ +import React from 'react' +import { createStackNavigator } from '@react-navigation/stack' +import { ChatRoomScreen } from '../screens' + +const Stack = createStackNavigator() + +export default function ChatNavigator() { + return ( + + + + ) +} diff --git a/front-end/app/src/navigation/MainNavigator.js b/front-end/app/src/navigation/MainNavigator.js index 8c0d46bd..2d30306a 100644 --- a/front-end/app/src/navigation/MainNavigator.js +++ b/front-end/app/src/navigation/MainNavigator.js @@ -1,81 +1,28 @@ import React from 'react' import { createStackNavigator } from '@react-navigation/stack' -import { LoginScreen } from '../screens/LoginScreen' -import { SignUpScreen } from '../screens/SignUpScreen' -import { TabNavigator } from './TabNavigator' -import { - ReportScreen, - CreateReportScreen, - ChatRoomScreen, - UserUpdateScreen, - UserAddScreen, - UserMgtScreen, - UnitMgtScreen, - ProcMgtScreen, -} from '../screens' +import TabNavigator from './TabNavigator' +import ReportNavigator from './ReportNavigator' +import ChatNavigator from './ChatNavigator' +import SettingNavigator from './SettingNavigator' +import { LoginScreen, SignUpScreen } from '../screens' const Stack = createStackNavigator() export default function MainNavigator({ route }) { return ( + - - - - - - - - - - + + + + ) } diff --git a/front-end/app/src/navigation/ReportNavigator.js b/front-end/app/src/navigation/ReportNavigator.js index 7f9c364b..96b4931b 100644 --- a/front-end/app/src/navigation/ReportNavigator.js +++ b/front-end/app/src/navigation/ReportNavigator.js @@ -1,31 +1,22 @@ -import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs' +import React from 'react' +import { createStackNavigator } from '@react-navigation/stack' +import { ReportScreen, CreateReportScreen } from '../screens' -import { Colors } from 'react-native-paper' -import { RecdReportScreen, SentReportScreen } from '../screens' +const Stack = createStackNavigator() -const Tab = createMaterialTopTabNavigator() - -export function ReportNavigator() { +export default function ReportNavigator() { return ( - - + - - + ) } diff --git a/front-end/app/src/navigation/SettingNavigator.js b/front-end/app/src/navigation/SettingNavigator.js new file mode 100644 index 00000000..3f1ad0e8 --- /dev/null +++ b/front-end/app/src/navigation/SettingNavigator.js @@ -0,0 +1,49 @@ +import React from 'react' +import { createStackNavigator } from '@react-navigation/stack' +import { + UserUpdateScreen, + UserAddScreen, + UserMgtScreen, + UnitMgtScreen, + UnitAddScreen, + SysMgtScreen, +} from '../screens' + +const Stack = createStackNavigator() + +export default function SettingNavigator() { + return ( + + + + + + + + + ) +} diff --git a/front-end/app/src/navigation/TabNavigator.js b/front-end/app/src/navigation/TabNavigator.js index a418ade4..7bfee8b7 100644 --- a/front-end/app/src/navigation/TabNavigator.js +++ b/front-end/app/src/navigation/TabNavigator.js @@ -2,13 +2,13 @@ import React from 'react' import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' import { Colors } from 'react-native-paper' import Icon from 'react-native-vector-icons/MaterialCommunityIcons' -import { ReportNavigator } from './ReportNavigator' +import { TopNavigator } from './TopNavigator' import { ChatListScreen, OrgChartScreen, SettingScreen } from '../screens' const Tab = createBottomTabNavigator() const icons = { - ReportNavigator: ['note-text', 'note-text-outline'], + TopNavigator: ['note-text', 'note-text-outline'], ChatListScreen: ['message-text', 'message-text-outline'], OrgChartScreen: ['graph', 'graph-outline'], SettingScreen: ['cog', 'cog-outline'], @@ -31,13 +31,13 @@ const screenOptions = ({ route }) => { } } -export function TabNavigator() { +export default function TabNavigator() { return ( + + + + ) +} diff --git a/front-end/app/src/screens/index.js b/front-end/app/src/screens/index.js index 8a2e7b31..ce3a7d66 100644 --- a/front-end/app/src/screens/index.js +++ b/front-end/app/src/screens/index.js @@ -1,9 +1,10 @@ export * from './setting-screens/SettingScreen' export * from './setting-screens/UserMgtScreen' export * from './setting-screens/UnitMgtScreen' +export * from './setting-screens/UnitAddScreen' export * from './setting-screens/UserAddScreen' export * from './setting-screens/UserUpdateScreen' -export * from './setting-screens/ProcMgtScreen' +export * from './setting-screens/SysMgtScreen' export * from './report-screens/CreateReportScreen' export * from './report-screens/RecdReportScreen' export * from './report-screens/ReportScreen' diff --git a/front-end/app/src/screens/setting-screens/SettingScreen.js b/front-end/app/src/screens/setting-screens/SettingScreen.js index f341ea9b..e7203e94 100644 --- a/front-end/app/src/screens/setting-screens/SettingScreen.js +++ b/front-end/app/src/screens/setting-screens/SettingScreen.js @@ -77,6 +77,12 @@ export function SettingScreen() { style={styles.listItem} onPress={() => navigation.navigate('UnitMgtScreen')} /> + } + style={styles.listItem} + onPress={() => navigation.navigate('UnitAddScreen')} + /> } diff --git a/front-end/app/src/screens/setting-screens/ProcMgtScreen.js b/front-end/app/src/screens/setting-screens/SysMgtScreen.js similarity index 90% rename from front-end/app/src/screens/setting-screens/ProcMgtScreen.js rename to front-end/app/src/screens/setting-screens/SysMgtScreen.js index dd01c20b..f76b56a6 100644 --- a/front-end/app/src/screens/setting-screens/ProcMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/SysMgtScreen.js @@ -3,7 +3,7 @@ import { SafeAreaView } from 'react-native' import { ReportGroup } from '../../components/ReportGroup' import DATA from '../../data/procData' -export function ProcMgtScreen() { +export function SysMgtScreen() { return ( diff --git a/front-end/app/src/screens/setting-screens/UnitAddScreen.js b/front-end/app/src/screens/setting-screens/UnitAddScreen.js new file mode 100644 index 00000000..e6e56775 --- /dev/null +++ b/front-end/app/src/screens/setting-screens/UnitAddScreen.js @@ -0,0 +1,66 @@ +import React, { useState } from 'react' +import { SafeAreaView, View, StyleSheet, Alert } from 'react-native' +import { TextInput } from 'react-native-paper' +import { ImagePicker } from '../../components/ImagePicker' +import { window } from '../../constants/layout' +import addUnitApi from '../../apis/addUnitApi' +import { MyButton } from '../../components/MyButton' + +export function UnitAddScreen() { + const addUnitHandler = async ({ Unitname, Unitslogan }) => { + const res = await addUnitApi({ Unitname, Unitslogan }) + if (res.Unitname) { + Alert.alert('업데이트에 성공하였습니다.') + } else { + Alert.alert(res.message) + } + } + + const [Unitname, setUnitname] = useState('') + const [Unitslogan, setUnitslogan] = useState('') + const [Logo, setLogo] = useState('') + + return ( + + + setUnitname(Unitname)} + style={styles.textInput} + /> + setUnitslogan(Unitslogan)} + style={styles.textInput} + /> + + + addUnitHandler({ Unitname, Unitslogan, Logo })} + /> + + ) +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: 'white', + alignItems: 'center', + }, + view: { + width: '85%', + alignItems: 'center', + marginBottom: (20 / 812) * window.height, + }, + textInput: { + width: '100%', + backgroundColor: 'white', + marginBottom: (15 / 812) * window.height, + }, +}) diff --git a/front-end/app/src/screens/setting-screens/UnitMgtScreen.js b/front-end/app/src/screens/setting-screens/UnitMgtScreen.js index 7a2edf77..09f57b56 100644 --- a/front-end/app/src/screens/setting-screens/UnitMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/UnitMgtScreen.js @@ -3,12 +3,22 @@ import { SafeAreaView, View, StyleSheet, Alert } from 'react-native' import { TextInput } from 'react-native-paper' import { ImagePicker } from '../../components/ImagePicker' import { window } from '../../constants/layout' -import addUnitApi from '../../apis/addUnitApi' +import updateUnitApi from '../../apis/addUnitApi' +import updateUnitLogoApi from '../../apis/updateUnitLogoApi' import { MyButton } from '../../components/MyButton' export function UnitMgtScreen() { - const addUnitHandler = async ({ Unitname, Unitslogan, Logo }) => { - const res = await addUnitApi({ Unitname, Unitslogan, Logo }) + const updateUnitHandler = async ({ Unitname, Unitslogan }) => { + const res = await updateUnitApi({ Unitname, Unitslogan }) + if (res.Unitname) { + Alert.alert('업데이트에 성공하였습니다.') + } else { + Alert.alert(res.message) + } + } + + const updateUnitLogoHandler = async ({ Logo }) => { + const res = await updateUnitLogoApi({ Logo }) if (res.Unitname) { Alert.alert('업데이트에 성공하였습니다.') } else { @@ -24,25 +34,25 @@ export function UnitMgtScreen() { setUnitname(Unitname)} style={styles.textInput} /> setUnitslogan(Unitslogan)} style={styles.textInput} /> - addUnitHandler({ Unitname, Unitslogan, Logo })} + onPress={() => updateUnitHandler({ Unitname, Unitslogan })} /> + ) } diff --git a/front-end/app/src/screens/setting-screens/UserUpdateScreen.js b/front-end/app/src/screens/setting-screens/UserUpdateScreen.js index 6ca6b7e8..ff5634fa 100644 --- a/front-end/app/src/screens/setting-screens/UserUpdateScreen.js +++ b/front-end/app/src/screens/setting-screens/UserUpdateScreen.js @@ -7,14 +7,13 @@ import { window } from '../../constants/layout' import DropDownPicker from 'react-native-dropdown-picker' import { MyButton } from '../../components/MyButton' import updateUserApi from '../../apis/updateUserApi' +import updateUserPicApi from '../../apis/updateUserPic' import { userState } from '../../states/userState' import { useRecoilState } from 'recoil' export function UserUpdateScreen() { const [userMe, setUserMe] = useRecoilState(userState) - console.log(userMe.Name) - const updateUserHandler = useCallback( async ({ Rank, Name, email, milNumber, Number }) => { const res = await updateUserApi({ @@ -32,6 +31,17 @@ export function UserUpdateScreen() { } ) + const updateUserPicHandler = useCallback(async ({ pic }) => { + const res = await updateUserApi({ + pic, + }) + if (res.message) Alert.alert(res.message) + else { + setUserMe({ ...userMe, pic }) + Alert.alert('사용자 이미지 정보가 변경되었습니다.') + } + }) + const [Name, setName] = useState(userMe.Name) const [email, setEmail] = useState(userMe.email) const [Number, setNumber] = useState(userMe.Number) From 547370dae192ff8be87ba983fd2f25fb04ff4814 Mon Sep 17 00:00:00 2001 From: hyeongmin Kim <113012760+gudmin0526@users.noreply.github.com> Date: Mon, 17 Oct 2022 14:08:23 +0000 Subject: [PATCH 11/48] Feat: Add unit, user update api --- .../{updateUserPic.js => updateUserPicApi.js} | 0 .../app/src/components/ImagePicker/index.js | 2 +- front-end/app/src/navigation/MainNavigator.js | 2 +- front-end/app/src/navigation/TabNavigator.js | 2 +- front-end/app/src/navigation/TopNavigator.js | 2 +- .../screens/setting-screens/UnitAddScreen.js | 8 ++-- .../screens/setting-screens/UnitMgtScreen.js | 18 ++++---- .../setting-screens/UserUpdateScreen.js | 42 ++++++++++++------- 8 files changed, 45 insertions(+), 31 deletions(-) rename front-end/app/src/apis/{updateUserPic.js => updateUserPicApi.js} (100%) diff --git a/front-end/app/src/apis/updateUserPic.js b/front-end/app/src/apis/updateUserPicApi.js similarity index 100% rename from front-end/app/src/apis/updateUserPic.js rename to front-end/app/src/apis/updateUserPicApi.js diff --git a/front-end/app/src/components/ImagePicker/index.js b/front-end/app/src/components/ImagePicker/index.js index 3d87ce34..5f22b29d 100644 --- a/front-end/app/src/components/ImagePicker/index.js +++ b/front-end/app/src/components/ImagePicker/index.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React from 'react' import * as ExpoImagePicker from 'expo-image-picker' import { Pressable, Image, Text, View } from 'react-native' import { styles } from './style' diff --git a/front-end/app/src/navigation/MainNavigator.js b/front-end/app/src/navigation/MainNavigator.js index 2d30306a..f59f2a01 100644 --- a/front-end/app/src/navigation/MainNavigator.js +++ b/front-end/app/src/navigation/MainNavigator.js @@ -8,7 +8,7 @@ import { LoginScreen, SignUpScreen } from '../screens' const Stack = createStackNavigator() -export default function MainNavigator({ route }) { +export default function MainNavigator() { return ( { + const addUnitHandler = useCallback(async ({ Unitname, Unitslogan }) => { const res = await addUnitApi({ Unitname, Unitslogan }) if (res.Unitname) { Alert.alert('업데이트에 성공하였습니다.') } else { Alert.alert(res.message) } - } + }, []) const [Unitname, setUnitname] = useState('') const [Unitslogan, setUnitslogan] = useState('') - const [Logo, setLogo] = useState('') + const [Logo, setLogo] = useState('')s return ( diff --git a/front-end/app/src/screens/setting-screens/UnitMgtScreen.js b/front-end/app/src/screens/setting-screens/UnitMgtScreen.js index 09f57b56..1b444375 100644 --- a/front-end/app/src/screens/setting-screens/UnitMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/UnitMgtScreen.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React, { useState, useCallback } from 'react' import { SafeAreaView, View, StyleSheet, Alert } from 'react-native' import { TextInput } from 'react-native-paper' import { ImagePicker } from '../../components/ImagePicker' @@ -8,23 +8,23 @@ import updateUnitLogoApi from '../../apis/updateUnitLogoApi' import { MyButton } from '../../components/MyButton' export function UnitMgtScreen() { - const updateUnitHandler = async ({ Unitname, Unitslogan }) => { + const updateUnitHandler = useCallback(async ({ Unitname, Unitslogan }) => { const res = await updateUnitApi({ Unitname, Unitslogan }) if (res.Unitname) { - Alert.alert('업데이트에 성공하였습니다.') + Alert.alert('부대 정보 업데이트에 성공하였습니다.') } else { Alert.alert(res.message) } - } + }, []) - const updateUnitLogoHandler = async ({ Logo }) => { + const updateUnitLogoHandler = useCallback(async ({ Logo }) => { const res = await updateUnitLogoApi({ Logo }) if (res.Unitname) { - Alert.alert('업데이트에 성공하였습니다.') + Alert.alert('부대 로고 업데이트에 성공하였습니다.') } else { Alert.alert(res.message) } - } + }, []) const [Unitname, setUnitname] = useState('') const [Unitslogan, setUnitslogan] = useState('') @@ -53,6 +53,10 @@ export function UnitMgtScreen() { onPress={() => updateUnitHandler({ Unitname, Unitslogan })} /> + updateUnitLogoHandler({ Logo })} + /> ) } diff --git a/front-end/app/src/screens/setting-screens/UserUpdateScreen.js b/front-end/app/src/screens/setting-screens/UserUpdateScreen.js index ff5634fa..621ce1e1 100644 --- a/front-end/app/src/screens/setting-screens/UserUpdateScreen.js +++ b/front-end/app/src/screens/setting-screens/UserUpdateScreen.js @@ -7,9 +7,10 @@ import { window } from '../../constants/layout' import DropDownPicker from 'react-native-dropdown-picker' import { MyButton } from '../../components/MyButton' import updateUserApi from '../../apis/updateUserApi' -import updateUserPicApi from '../../apis/updateUserPic' +import updateUserPicApi from '../../apis/updateUserPicApi' import { userState } from '../../states/userState' import { useRecoilState } from 'recoil' +import { ImagePicker } from '../../components/ImagePicker' export function UserUpdateScreen() { const [userMe, setUserMe] = useRecoilState(userState) @@ -32,7 +33,7 @@ export function UserUpdateScreen() { ) const updateUserPicHandler = useCallback(async ({ pic }) => { - const res = await updateUserApi({ + const res = await updateUserPicApi({ pic, }) if (res.message) Alert.alert(res.message) @@ -51,6 +52,8 @@ export function UserUpdateScreen() { const [Rank, setRank] = useState(userMe.Rank) const [Ranks, setRanks] = useState(RankItems) + const [pic, setPic] = useState('') + return ( @@ -117,20 +120,27 @@ export function UserUpdateScreen() { - {Rank && Name && Number && email && milNumber && ( - - updateUserHandler({ - Rank, - Name, - email, - Number, - milNumber, - }) - } - /> - )} + + updateUserHandler({ + Rank, + Name, + email, + Number, + milNumber, + }) + } + /> + + + updateUserPicHandler({ + pic, + }) + } + /> ) From 65289b7387849204af567907abbf9f80f6059dba Mon Sep 17 00:00:00 2001 From: Yunseong Choe <68419358+marunemo@users.noreply.github.com> Date: Mon, 17 Oct 2022 14:39:29 +0000 Subject: [PATCH 12/48] [Feat]Set drop down for memonote type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 메모보고 종류를 고를 수 있는 drop down 생성 --- front-end/web-next/pages/memonote.js | 15 +++++++++++++-- front-end/web-next/styles/globals.css | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/front-end/web-next/pages/memonote.js b/front-end/web-next/pages/memonote.js index d75076ec..432e25cc 100644 --- a/front-end/web-next/pages/memonote.js +++ b/front-end/web-next/pages/memonote.js @@ -1,6 +1,6 @@ import { useState } from 'react'; import Head from 'next/head' -import { Layout, Row, Col, List, Button, Input, Divider } from 'antd'; +import { Layout, Row, Col, List, Button, Input, Divider, Select } from 'antd'; import { FormOutlined } from '@ant-design/icons'; import ReportLayout from '../componenets/MemoReport'; import MemoForm from '../componenets/MemoForm'; @@ -8,6 +8,7 @@ import Styles from '../styles/MemoLayout.module.css'; export default function Memo() { const [selectedItem, setSelection] = useState(undefined); + const [memonoteType, setMemonoteType] = useState('받은 메모 보고'); const [formOpened, setFormOpened] = useState(false); const sampleData = [ @@ -91,7 +92,17 @@ export default function Memo() { justify="space-between" > -
받은 메모 보고
+
+ +
-

{error}

- +
+ +

{error}

+
계정이 없으세요? 회원가입하기

비밀번호를 잃어버리셨나요? 비밀번호 찾기
-
-

데모

- 대대장님 계정 데모:

- 수도방위사령부 제1방공여단 3대대 대대장 중령 김기철의 계정을 채험해 보세요!

- 용사 계정 데모:

- 수도방위사령부 제1방공여단 3대대에서 근무중인 상병 김형민의 계정을 채험해 보세요!

- +
+

프로젝트 데모

+
+ + 수방사 제1방공여단 3대대 대대장 중령 김기철의 계정 채험하기!

+ + 수방 제1방공여단 3대대에서 근무중인 상병 김형민의 계정 채험하기!

diff --git a/front-end/web-next/styles/Home.module.css b/front-end/web-next/styles/Home.module.css index 2eb15fa6..befd6a9b 100644 --- a/front-end/web-next/styles/Home.module.css +++ b/front-end/web-next/styles/Home.module.css @@ -1,12 +1,11 @@ - .inputfield { width: 400px; height: 25px; font-size: 17px; display: block; - border-top: none; - border-left: none; - border-right: none; + border-top: none; + border-left: none; + border-right: none; } .buttonfield { @@ -14,53 +13,81 @@ height: 33px; font-size: 18px; background-color: #008272; - color: white; + color: white; border-radius: 5px; border: none; margin-top: 5px; display: block; + letter-spacing: 3px; } .buttonfield:hover { - cursor: pointer; + cursor: pointer; background-color: #016459; } -.inputfield:focus{ +.horizontalline { + border: 1px solid grey; +} + +.buttonfielddemo { + width: 180px; + height: 33px; + font-size: 14px; + background-color: #008272; + color: white; + border-radius: 5px; + border: none; + display: block; + letter-spacing: 0.8px; + margin-top: 5px; +} + +.inputfield:focus { outline: none; - border-bottom: 2px solid black; + border-bottom: 2px solid black; } + #loginfooter { width: 400px; margin: auto; margin-top: 20px; } + #demofooter { + position: absolute; + left: 50%; + transform: translate(-50%); + bottom: 330px; width: 400px; - margin: auto; - margin-top: 55px; } + #demofooterh2 { text-align: center; - margin-bottom: 10px; + font-weight: bold; + margin-bottom: 1px; + letter-spacing: 2px; } + .desctext { - font-size: 10px; + font-size: 12px; + letter-spacing: 0.8px; } #demofooter button { background-color: #008272; - color: white; + color: white; border-radius: 5px; border: none; - margin-top: 5px; + margin-top: 10px; height: 28px; padding-left: 10px; padding-right: 10px; } + #demofooter button:hover { - cursor: pointer; + cursor: pointer; background-color: #016459; } @@ -68,17 +95,18 @@ color: blue; font-size: 15px; } + .links:hover { - color:rgb(0, 0, 158); + color: rgb(0, 0, 158); text-decoration: underline; } #error { - color: red; - font-size: 14px; + color: red; + font-size: 14px; margin-left: 15px; - line-height: 33px; + line-height: 33px; margin-top: 4px; margin-bottom: 0px; } \ No newline at end of file diff --git a/front-end/web-next/styles/notloggedinlayout.module.css b/front-end/web-next/styles/notloggedinlayout.module.css index 22240402..734973a5 100644 --- a/front-end/web-next/styles/notloggedinlayout.module.css +++ b/front-end/web-next/styles/notloggedinlayout.module.css @@ -32,7 +32,9 @@ } #childcontainer { + position: relative; width: 500px; + height: 100%; margin: auto; } \ No newline at end of file From 17adf0f7b0ec6011eaadfe6e334b97e334e9df43 Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Tue, 18 Oct 2022 14:02:04 +0000 Subject: [PATCH 14/48] [Feat]: #107 Register page enhanced --- front-end/web-next/pages/register.js | 13 +++---------- front-end/web-next/styles/register.module.css | 11 +++-------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/front-end/web-next/pages/register.js b/front-end/web-next/pages/register.js index e4c9de63..1cd16c83 100644 --- a/front-end/web-next/pages/register.js +++ b/front-end/web-next/pages/register.js @@ -58,27 +58,20 @@ const Register = () => { 회원가입 -

회원가입

+

회원가입

{ setName(event.target.value) }} /> -

- { setDoDID(event.target.value) }} /> - 22-xxxxxxxx 양식으로 입력 + { setDoDID(event.target.value) }} /> -

- { setInvcode(event.target.value) }} /> - 부대에서 받은 초대코드 이용 + { setInvcode(event.target.value) }} /> -

{ setPassword(event.target.value) }} /> - 8자리 이상 비밀번호 사용 -

({ validator(_, value) { if (!value || getFieldValue('비밀번호') === value) { diff --git a/front-end/web-next/styles/register.module.css b/front-end/web-next/styles/register.module.css index 0a85c177..1ddf165a 100644 --- a/front-end/web-next/styles/register.module.css +++ b/front-end/web-next/styles/register.module.css @@ -19,6 +19,7 @@ border: none; margin-top: 5px; display: block; + letter-spacing: 1.5px; } .buttonfield:hover { @@ -30,12 +31,6 @@ margin-bottom: 0px; } -.inputdesc { - color: darkgrey; - font-size: 13px; - line-height: 13px; - margin-top: 0px; -} #loginfooter { width: 400px; @@ -71,5 +66,5 @@ } .inputfield { - margin-bottom: 7px; -} \ No newline at end of file + margin-bottom: 20px; +} From c8c65f8f4e108a680a4744c8832fb767eae890db Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Tue, 18 Oct 2022 14:20:21 +0000 Subject: [PATCH 15/48] [Refactor]: changed database schema --- back-end/models/userModel.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/back-end/models/userModel.js b/back-end/models/userModel.js index a9e63ae9..cfdaae87 100644 --- a/back-end/models/userModel.js +++ b/back-end/models/userModel.js @@ -33,19 +33,23 @@ const userSchema = mongoose.Schema({ }, Position: { type: String, - required: false + required: false, + default: "no data" }, email: { type: String, - required: false + required: false, + default: "no data" }, milNumber: { type: String, - required: false + required: false, + default: "no data" }, number: { type: String, - required: false + required: false, + default: "no data" }, pic: { type: String, @@ -58,7 +62,7 @@ const userSchema = mongoose.Schema({ }, is_registered: { type: Boolean, - default: false + default: false, }, myReportCards :[{ type: mongoose.Schema.Types.ObjectId, From 2c56aa098858a4d1ff4dea25d6ebdb5008caf330 Mon Sep 17 00:00:00 2001 From: hyeongmin Kim <113012760+gudmin0526@users.noreply.github.com> Date: Tue, 18 Oct 2022 23:51:07 +0000 Subject: [PATCH 16/48] Refactor: refactor apis. --- .../src/apis/{ => report}/addCommentApi.js | 2 +- .../app/src/apis/{ => report}/addReportApi.js | 2 +- .../src/apis/{ => report}/fetchReportApi.js | 2 +- front-end/app/src/apis/{ => sign}/loginApi.js | 2 +- .../app/src/apis/{ => sign}/logoutApi.js | 2 +- .../app/src/apis/{ => sign}/registerApi.js | 2 +- front-end/app/src/apis/sys/addSysApi.js | 0 front-end/app/src/apis/sys/fetchSysApi.js | 0 .../app/src/apis/{ => unit}/addUnitApi.js | 2 +- .../app/src/apis/{ => unit}/updateUnitApi.js | 2 +- .../src/apis/{ => unit}/updateUnitLogoApi.js | 2 +- .../app/src/apis/{ => user}/addUserApi.js | 2 +- .../app/src/apis/{ => user}/searchUserApi.js | 2 +- .../app/src/apis/{ => user}/updateUserApi.js | 2 +- .../src/apis/{ => user}/updateUserPicApi.js | 2 +- .../app/src/components/ReportGroup/index.js | 9 +- .../screens/chat-screens/ChatRoomScreen.js | 8 ++ .../report-screens/CreateReportScreen.js | 16 ---- .../report-screens/RecdReportScreen.js | 4 +- .../report-screens/SentReportScreen.js | 85 ++++++++++++++++--- .../screens/setting-screens/SysMgtScreen.js | 18 +++- .../screens/setting-screens/UserMgtScreen.js | 10 ++- 22 files changed, 120 insertions(+), 56 deletions(-) rename front-end/app/src/apis/{ => report}/addCommentApi.js (95%) rename front-end/app/src/apis/{ => report}/addReportApi.js (95%) rename front-end/app/src/apis/{ => report}/fetchReportApi.js (95%) rename front-end/app/src/apis/{ => sign}/loginApi.js (92%) rename front-end/app/src/apis/{ => sign}/logoutApi.js (85%) rename front-end/app/src/apis/{ => sign}/registerApi.js (94%) create mode 100644 front-end/app/src/apis/sys/addSysApi.js create mode 100644 front-end/app/src/apis/sys/fetchSysApi.js rename front-end/app/src/apis/{ => unit}/addUnitApi.js (94%) rename front-end/app/src/apis/{ => unit}/updateUnitApi.js (94%) rename front-end/app/src/apis/{ => unit}/updateUnitLogoApi.js (94%) rename front-end/app/src/apis/{ => user}/addUserApi.js (94%) rename front-end/app/src/apis/{ => user}/searchUserApi.js (94%) rename front-end/app/src/apis/{ => user}/updateUserApi.js (94%) rename front-end/app/src/apis/{ => user}/updateUserPicApi.js (94%) diff --git a/front-end/app/src/apis/addCommentApi.js b/front-end/app/src/apis/report/addCommentApi.js similarity index 95% rename from front-end/app/src/apis/addCommentApi.js rename to front-end/app/src/apis/report/addCommentApi.js index ef5c209a..03fdbd87 100644 --- a/front-end/app/src/apis/addCommentApi.js +++ b/front-end/app/src/apis/report/addCommentApi.js @@ -1,4 +1,4 @@ -import URL from '../../url' +import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' const addCommentApi = async ({ Type, Content, Title }) => { diff --git a/front-end/app/src/apis/addReportApi.js b/front-end/app/src/apis/report/addReportApi.js similarity index 95% rename from front-end/app/src/apis/addReportApi.js rename to front-end/app/src/apis/report/addReportApi.js index c1d55831..9683b449 100644 --- a/front-end/app/src/apis/addReportApi.js +++ b/front-end/app/src/apis/report/addReportApi.js @@ -1,4 +1,4 @@ -import URL from '../../url' +import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' const addReportApi = async ({ diff --git a/front-end/app/src/apis/fetchReportApi.js b/front-end/app/src/apis/report/fetchReportApi.js similarity index 95% rename from front-end/app/src/apis/fetchReportApi.js rename to front-end/app/src/apis/report/fetchReportApi.js index a84983d1..ce9993f6 100644 --- a/front-end/app/src/apis/fetchReportApi.js +++ b/front-end/app/src/apis/report/fetchReportApi.js @@ -1,4 +1,4 @@ -import URL from '../../url' +import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' const fetchReportApi = async ({ diff --git a/front-end/app/src/apis/loginApi.js b/front-end/app/src/apis/sign/loginApi.js similarity index 92% rename from front-end/app/src/apis/loginApi.js rename to front-end/app/src/apis/sign/loginApi.js index cdf7672d..3b7cc7e3 100644 --- a/front-end/app/src/apis/loginApi.js +++ b/front-end/app/src/apis/sign/loginApi.js @@ -1,4 +1,4 @@ -import URL from '../../url' +import URL from '../../../url' const loginApi = async ({ DoDID, password }) => { try { diff --git a/front-end/app/src/apis/logoutApi.js b/front-end/app/src/apis/sign/logoutApi.js similarity index 85% rename from front-end/app/src/apis/logoutApi.js rename to front-end/app/src/apis/sign/logoutApi.js index 68f2830a..ee09650a 100644 --- a/front-end/app/src/apis/logoutApi.js +++ b/front-end/app/src/apis/sign/logoutApi.js @@ -1,4 +1,4 @@ -import URL from '../../url' +import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' const logoutApi = async () => { diff --git a/front-end/app/src/apis/registerApi.js b/front-end/app/src/apis/sign/registerApi.js similarity index 94% rename from front-end/app/src/apis/registerApi.js rename to front-end/app/src/apis/sign/registerApi.js index adf40688..7427db8d 100644 --- a/front-end/app/src/apis/registerApi.js +++ b/front-end/app/src/apis/sign/registerApi.js @@ -1,4 +1,4 @@ -import URL from '../../url' +import URL from '../../../url' const registerApi = async ({ Rank, diff --git a/front-end/app/src/apis/sys/addSysApi.js b/front-end/app/src/apis/sys/addSysApi.js new file mode 100644 index 00000000..e69de29b diff --git a/front-end/app/src/apis/sys/fetchSysApi.js b/front-end/app/src/apis/sys/fetchSysApi.js new file mode 100644 index 00000000..e69de29b diff --git a/front-end/app/src/apis/addUnitApi.js b/front-end/app/src/apis/unit/addUnitApi.js similarity index 94% rename from front-end/app/src/apis/addUnitApi.js rename to front-end/app/src/apis/unit/addUnitApi.js index 4860608f..289dd48a 100644 --- a/front-end/app/src/apis/addUnitApi.js +++ b/front-end/app/src/apis/unit/addUnitApi.js @@ -1,4 +1,4 @@ -import URL from '../../url' +import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' const addUnitApi = async ({ Unitname, Unitslogan, Logo }) => { diff --git a/front-end/app/src/apis/updateUnitApi.js b/front-end/app/src/apis/unit/updateUnitApi.js similarity index 94% rename from front-end/app/src/apis/updateUnitApi.js rename to front-end/app/src/apis/unit/updateUnitApi.js index 7b389577..95b0141e 100644 --- a/front-end/app/src/apis/updateUnitApi.js +++ b/front-end/app/src/apis/unit/updateUnitApi.js @@ -1,4 +1,4 @@ -import URL from '../../url' +import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' const updateUnitApi = async ({ Unitname, Unitslogan }) => { diff --git a/front-end/app/src/apis/updateUnitLogoApi.js b/front-end/app/src/apis/unit/updateUnitLogoApi.js similarity index 94% rename from front-end/app/src/apis/updateUnitLogoApi.js rename to front-end/app/src/apis/unit/updateUnitLogoApi.js index 8d79c5eb..fff858ce 100644 --- a/front-end/app/src/apis/updateUnitLogoApi.js +++ b/front-end/app/src/apis/unit/updateUnitLogoApi.js @@ -1,4 +1,4 @@ -import URL from '../../url' +import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' const updateUnitLogoApi = async ({ Logo }) => { diff --git a/front-end/app/src/apis/addUserApi.js b/front-end/app/src/apis/user/addUserApi.js similarity index 94% rename from front-end/app/src/apis/addUserApi.js rename to front-end/app/src/apis/user/addUserApi.js index 7ee648df..0c04f23d 100644 --- a/front-end/app/src/apis/addUserApi.js +++ b/front-end/app/src/apis/user/addUserApi.js @@ -1,4 +1,4 @@ -import URL from '../../url' +import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' const addUserApi = async ({ Rank, Name, DoDID, Type }) => { diff --git a/front-end/app/src/apis/searchUserApi.js b/front-end/app/src/apis/user/searchUserApi.js similarity index 94% rename from front-end/app/src/apis/searchUserApi.js rename to front-end/app/src/apis/user/searchUserApi.js index 44d9eb42..c1816305 100644 --- a/front-end/app/src/apis/searchUserApi.js +++ b/front-end/app/src/apis/user/searchUserApi.js @@ -1,4 +1,4 @@ -import URL from '../../url' +import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' const searchUserApi = async (query) => { diff --git a/front-end/app/src/apis/updateUserApi.js b/front-end/app/src/apis/user/updateUserApi.js similarity index 94% rename from front-end/app/src/apis/updateUserApi.js rename to front-end/app/src/apis/user/updateUserApi.js index 4b3232b1..7b2e50da 100644 --- a/front-end/app/src/apis/updateUserApi.js +++ b/front-end/app/src/apis/user/updateUserApi.js @@ -1,4 +1,4 @@ -import URL from '../../url' +import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' const updateUserApi = async ({ Rank, Name, email, milNumber, Number }) => { diff --git a/front-end/app/src/apis/updateUserPicApi.js b/front-end/app/src/apis/user/updateUserPicApi.js similarity index 94% rename from front-end/app/src/apis/updateUserPicApi.js rename to front-end/app/src/apis/user/updateUserPicApi.js index 2bfbe5ad..ccf610f6 100644 --- a/front-end/app/src/apis/updateUserPicApi.js +++ b/front-end/app/src/apis/user/updateUserPicApi.js @@ -1,4 +1,4 @@ -import URL from '../../url' +import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' const updateUserPicApi = async ({ pic }) => { diff --git a/front-end/app/src/components/ReportGroup/index.js b/front-end/app/src/components/ReportGroup/index.js index aabb5d97..671ba17e 100644 --- a/front-end/app/src/components/ReportGroup/index.js +++ b/front-end/app/src/components/ReportGroup/index.js @@ -4,6 +4,8 @@ import { Avatar } from 'react-native-paper' import { styles } from './style' import { useNunitoFonts } from '../../hooks/useNunitoFonts' +// 배경 회색으로, 각 카드 elevation주기 + const ItemSeparator = () => ( ( {item.name} {item.position} - {/* - - */} ) diff --git a/front-end/app/src/screens/chat-screens/ChatRoomScreen.js b/front-end/app/src/screens/chat-screens/ChatRoomScreen.js index 005999ef..60923656 100644 --- a/front-end/app/src/screens/chat-screens/ChatRoomScreen.js +++ b/front-end/app/src/screens/chat-screens/ChatRoomScreen.js @@ -1,5 +1,6 @@ import React, { useState, useCallback, useEffect } from 'react' import { GiftedChat, Bubble } from 'react-native-gifted-chat' +import {Colors} from 'react-native-paper' function renderBubble(props) { return ( @@ -55,12 +56,19 @@ export function ChatRoomScreen() { return ( onSend(messages)} placeholder="메시지를 입력하세요." user={{ _id: 2, name: '김형민' }} + textInputStyle={{ + width: '96%', + backgroundColor: Colors.grey100, + elevation: 4, + }} + /> ) } diff --git a/front-end/app/src/screens/report-screens/CreateReportScreen.js b/front-end/app/src/screens/report-screens/CreateReportScreen.js index 4234ed2a..27242be2 100644 --- a/front-end/app/src/screens/report-screens/CreateReportScreen.js +++ b/front-end/app/src/screens/report-screens/CreateReportScreen.js @@ -12,17 +12,6 @@ import searchUserApi from '../../apis/searchUserApi' import DATA from '../../data/procData' import { window } from '../../constants/layout' -const rightIcon = ({ key, addedUser, setAddedUser }) => ( - idx.toString() !== key) - )} - /> -) - export function CreateReportScreen() { const fetchUserHandler = async (query) => { const res = await searchUserApi(query) @@ -135,11 +124,6 @@ export function CreateReportScreen() { name={user.Name} Position={user.Position} key={idx.toString()} - // right={rightIcon({ - // key: idx.toString(), - // addedUser, - // setAddedUser, - // })} /> ))} diff --git a/front-end/app/src/screens/report-screens/RecdReportScreen.js b/front-end/app/src/screens/report-screens/RecdReportScreen.js index 25638b9d..21832c49 100644 --- a/front-end/app/src/screens/report-screens/RecdReportScreen.js +++ b/front-end/app/src/screens/report-screens/RecdReportScreen.js @@ -69,8 +69,8 @@ const styles = StyleSheet.create({ }, fab: { borderRadius: 60, - height: 56, - width: 56, + height: 55, + width: 55, position: 'absolute', bottom: 15, right: 20, diff --git a/front-end/app/src/screens/report-screens/SentReportScreen.js b/front-end/app/src/screens/report-screens/SentReportScreen.js index 275ff489..a297c762 100644 --- a/front-end/app/src/screens/report-screens/SentReportScreen.js +++ b/front-end/app/src/screens/report-screens/SentReportScreen.js @@ -1,16 +1,79 @@ -import { View, Text } from 'react-native' +import React from 'react' +import { ReportListItem } from '../../components/ReportListItem' +// prettier-ignore +import { SafeAreaView, StyleSheet, ScrollView } from 'react-native' +import { Colors, FAB } from 'react-native-paper' +import { useNavigation } from '@react-navigation/native' +import moment from 'moment' +import fetchReportApi from '../../apis/fetchReportApi' + +const { Title, isEnd, Content, severity, date, Type } = { + Title: '3초소 거수자 발견', + isEnd: false, + Content: `충성! 당직사령님, 3초소에 사복을 입은 거수자가 나타났습니다.\n무기는 소지하고 있지 않은 것으로 보이며, 위병소 앞에서 두리번 거리고 있습니다.\n현재 경계중이며, 추가사항 발생시 보고드리겠습니다.`, + severity: 3, + date: `${moment().subtract(6, 'days').format('YYYY-MM-DD hh:mm')}`, + Type: '긴급상황', +} export function SentReportScreen() { + const navigation = useNavigation() + // const [reports, setReports] = useState(() => fetchReportHandler()) + return ( - - SentReportScreen - + + + + + + navigation.navigate('CreateReportScreen')} + style={styles.fab} + color="white" + /> + ) } + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: Colors.grey200, + paddingVertical: 5, + }, + scrollView: { + width: '100%', + alignItems: 'center', + }, + flexRow: { + flex: 1, + flexDirection: 'row', + }, + fab: { + borderRadius: 60, + height: 56, + width: 56, + position: 'absolute', + bottom: 15, + right: 20, + backgroundColor: '#009572', + }, +}) diff --git a/front-end/app/src/screens/setting-screens/SysMgtScreen.js b/front-end/app/src/screens/setting-screens/SysMgtScreen.js index f76b56a6..e4638b3e 100644 --- a/front-end/app/src/screens/setting-screens/SysMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/SysMgtScreen.js @@ -1,13 +1,25 @@ import React, { useState } from 'react' -import { SafeAreaView } from 'react-native' +import { SafeAreaView, ScrollView } from 'react-native' +import { Color, FAB } from 'react-native-paper' import { ReportGroup } from '../../components/ReportGroup' import DATA from '../../data/procData' +// fetch로 데이터를 받아와서 넘겨줌. +// 스크롤뷰로 나타냄. +// title을 체크해서 중복되면 삭제하고 다시 해달라고 alert. +// 꾹 눌러서 delete alert. +// 일단 add or delete +// FAB을 통해 add Screen or Modal +// 1. Modal이 나을듯 +// delete의 경우 button을 통해? + export function SysMgtScreen() { return ( - - + + + + ) } diff --git a/front-end/app/src/screens/setting-screens/UserMgtScreen.js b/front-end/app/src/screens/setting-screens/UserMgtScreen.js index ce1452ef..6e59c7ff 100644 --- a/front-end/app/src/screens/setting-screens/UserMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/UserMgtScreen.js @@ -13,7 +13,7 @@ const Item = ({ Name, Rank, pic, Position }) => ( {Name} {Position} - DELETE + Delete ) @@ -49,6 +49,7 @@ export function UserMgtScreen() { icon="account-plus" style={styles.fab} onPress={() => navigation.navigate('UserAddScreen')} + color="white" /> ) @@ -72,11 +73,12 @@ export const styles = StyleSheet.create({ alignItems: 'center', }, fab: { + backgroundColor: '#009572', borderRadius: 60, - height: 56, - width: 56, + height: 55, + width: 55, position: 'absolute', - bottom: 25, + bottom: 50, right: 20, }, image: { From 7698e4b4041ffea18211ebab301bc00e3649251b Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Wed, 19 Oct 2022 11:44:53 +0000 Subject: [PATCH 17/48] #108 User homepage Integration/keyvault testing --- .../web-next/encryption/userencryption.js | 22 + front-end/web-next/package-lock.json | 892 ++++++++++++++++++ front-end/web-next/package.json | 2 + front-end/web-next/pages/home.js | 132 +-- front-end/web-next/pages/index.js | 9 +- front-end/web-next/pages/register.js | 129 +-- 6 files changed, 1064 insertions(+), 122 deletions(-) create mode 100644 front-end/web-next/encryption/userencryption.js diff --git a/front-end/web-next/encryption/userencryption.js b/front-end/web-next/encryption/userencryption.js new file mode 100644 index 00000000..4d0cf757 --- /dev/null +++ b/front-end/web-next/encryption/userencryption.js @@ -0,0 +1,22 @@ +const { SecretClient } = require("@azure/keyvault-secrets"); +const { ClientSecretCredential } = require("@azure/identity"); +const tenantId = process.env.AZURE_TENANT_ID +const clientId = process.env.AZURE_CLIENT_ID +const clientSecret = process.env.AZURE_CLIENT_SECRET + +export async function encryptuser(id, plaintext) { + const credential = new ClientSecretCredential(tenantId, clientId, clientSecret); + const url = "https://" + 'vault-rokasrs' + ".vault.azure.net"; + const client = new SecretClient(url, credential); + console.log(client) + const secretName = 'secret1'; + const result = await client.setSecret(secretName, "MySecretValue"); + const secret = await client.getSecret(secretName); + console.log("secret: ", secret['value']); + return 'hi' + +} + +export async function decryptuser(ciphertext, id) { + +} \ No newline at end of file diff --git a/front-end/web-next/package-lock.json b/front-end/web-next/package-lock.json index bc16d884..ab2f77f7 100644 --- a/front-end/web-next/package-lock.json +++ b/front-end/web-next/package-lock.json @@ -9,6 +9,8 @@ "version": "0.1.0", "dependencies": { "@ant-design/icons": "^4.7.0", + "@azure/identity": "^3.0.0", + "@azure/keyvault-secrets": "^4.6.0", "antd": "^4.23.4", "bootstrap-icons": "^1.9.1", "buffer": "^6.0.3", @@ -91,6 +93,216 @@ "react": ">=16.9.0" } }, + "node_modules/@azure/abort-controller": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", + "integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==", + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-auth": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.4.0.tgz", + "integrity": "sha512-HFrcTgmuSuukRf/EdPmqBrc5l6Q5Uu+2TbuhaKbgaCpP2TfAeiNaQPAadxO+CYBRHGUzIDteMAjFspFLDLnKVQ==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-client": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.6.1.tgz", + "integrity": "sha512-mZ1MSKhZBYoV8GAWceA+PEJFWV2VpdNSpxxcj1wjIAOi00ykRuIQChT99xlQGZWLY3/NApWhSImlFwsmCEs4vA==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-rest-pipeline": "^1.9.1", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.0.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-http-compat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-1.3.0.tgz", + "integrity": "sha512-ZN9avruqbQ5TxopzG3ih3KRy52n8OAbitX3fnZT5go4hzu0J+KVPSzkL+Wt3hpJpdG8WIfg1sBD1tWkgUdEpBA==", + "dependencies": { + "@azure/abort-controller": "^1.0.4", + "@azure/core-client": "^1.3.0", + "@azure/core-rest-pipeline": "^1.3.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-lro": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.4.0.tgz", + "integrity": "sha512-F65+rYkll1dpw3RGm8/SSiSj+/QkMeYDanzS/QKlM1dmuneVyXbO46C88V1MRHluLGdMP6qfD3vDRYALn0z0tQ==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-paging": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.3.0.tgz", + "integrity": "sha512-H6Tg9eBm0brHqLy0OSAGzxIh1t4UL8eZVrSUMJ60Ra9cwq2pOskFqVpz2pYoHDsBY1jZ4V/P8LRGb5D5pmC6rg==", + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.9.2.tgz", + "integrity": "sha512-8rXI6ircjenaLp+PkOFpo37tQ1PQfztZkfVj97BIF3RPxHAsoVSgkJtu3IK/bUEWcb7HzXSoyBe06M7ODRkRyw==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.0.0", + "@azure/logger": "^1.0.0", + "form-data": "^4.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "tslib": "^2.2.0", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-tracing": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.1.tgz", + "integrity": "sha512-I5CGMoLtX+pI17ZdiFJZgxMJApsK6jjfm85hpgp3oazCdq5Wxgh4wMr7ge/TTWW1B5WBuvIOI1fMU/FrOAMKrw==", + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-util": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.1.1.tgz", + "integrity": "sha512-A4TBYVQCtHOigFb2ETiiKFDocBoI1Zk2Ui1KpI42aJSIDexF7DHQFpnjonltXAIU/ceH+1fsZAWWgvX6/AKzog==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/identity": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-3.0.0.tgz", + "integrity": "sha512-MAwrefZE6T15wJe/tOA6dffdTNCh+S6DOQe2otO6drEEVCHDF0zb+GItlK6kQzD5hPm/YueFCW6sN1q6F4XYuQ==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.4.0", + "@azure/core-rest-pipeline": "^1.1.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.0.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^2.26.0", + "@azure/msal-common": "^7.0.0", + "@azure/msal-node": "^1.10.0", + "events": "^3.0.0", + "jws": "^4.0.0", + "open": "^8.0.0", + "stoppable": "^1.1.0", + "tslib": "^2.2.0", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/keyvault-secrets": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@azure/keyvault-secrets/-/keyvault-secrets-4.6.0.tgz", + "integrity": "sha512-MDqsyODCGC2srqLKmO6MFw9WdgLrbPsfCNxgbekHXEd6XKM6KKyBlup5joj96EmdfZnXDFriecAIpj0Dtu81RQ==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.5.0", + "@azure/core-http-compat": "^1.3.0", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.1.1", + "@azure/core-rest-pipeline": "^1.8.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.0.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/logger": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.3.tgz", + "integrity": "sha512-aK4s3Xxjrx3daZr3VylxejK3vG5ExXck5WOHDJ8in/k9AqlfIyFMMT1uG7u8mNjX+QRILTIn0/Xgschfh/dQ9g==", + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/msal-browser": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-2.30.0.tgz", + "integrity": "sha512-4Y9+rjJiTFP7KEmuq1btmIrBgk0ImNyKsXj6A6NHZALd1X0M6W7L7kxpH6F+d1tEkMv8bYnZdn7IcauXbL8Llw==", + "dependencies": { + "@azure/msal-common": "^7.6.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-7.6.0.tgz", + "integrity": "sha512-XqfbglUTVLdkHQ8F9UQJtKseRr3sSnr9ysboxtoswvaMVaEfvyLtMoHv9XdKUfOc0qKGzNgRFd9yRjIWVepl6Q==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.14.2.tgz", + "integrity": "sha512-t3whVhhLdZVVeDEtUPD2Wqfa8BDi3EDMnpWp8dbuRW0GhUpikBfs4AQU0Fe6P9zS87n9LpmUTLrIcPEEuzkvfA==", + "dependencies": { + "@azure/msal-common": "^7.6.0", + "jsonwebtoken": "^8.5.1", + "uuid": "^8.3.0" + }, + "engines": { + "node": "10 || 12 || 14 || 16 || 18" + } + }, "node_modules/@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -1030,6 +1242,14 @@ "tslib": "^2.4.0" } }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "engines": { + "node": ">= 10" + } + }, "node_modules/@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", @@ -1197,6 +1417,17 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1403,6 +1634,11 @@ "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -1551,6 +1787,11 @@ "ieee754": "^1.2.1" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -1657,6 +1898,17 @@ "node": ">=0.1.90" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/compute-scroll-into-view": { "version": "1.0.17", "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz", @@ -1847,6 +2099,14 @@ "node": ">=0.10.0" } }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, "node_modules/define-properties": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", @@ -1863,6 +2123,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -1894,6 +2162,14 @@ "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.3.tgz", "integrity": "sha512-Gj9hZN3a07cbR6zviMUBOMPdWxYhbMI+x+WS0NAIu2zFZmbK8ys9R79g+iG9qLnlCwpFoaB+fKy8Pdv470GsPA==" }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.271", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.271.tgz", @@ -2431,6 +2707,14 @@ "node": ">=0.10.0" } }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2569,6 +2853,19 @@ "is-callable": "^1.1.3" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/formik": { "version": "2.2.9", "resolved": "https://registry.npmjs.org/formik/-/formik-2.2.9.tgz", @@ -2853,6 +3150,31 @@ "react-is": "^16.7.0" } }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -3026,6 +3348,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3196,6 +3532,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3289,6 +3636,54 @@ "json5": "lib/cli.js" } }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jsonwebtoken/node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jsonwebtoken/node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -3303,6 +3698,25 @@ "node": ">=4.0" } }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -3366,6 +3780,36 @@ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "peer": true }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3373,6 +3817,11 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -3427,6 +3876,25 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3658,6 +4126,22 @@ "wrappy": "1" } }, + "node_modules/open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -4805,6 +5289,15 @@ "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==" }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, "node_modules/string-convert": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", @@ -5170,6 +5663,14 @@ "which-typed-array": "^1.1.2" } }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5364,6 +5865,171 @@ "resize-observer-polyfill": "^1.5.1" } }, + "@azure/abort-controller": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", + "integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==", + "requires": { + "tslib": "^2.2.0" + } + }, + "@azure/core-auth": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.4.0.tgz", + "integrity": "sha512-HFrcTgmuSuukRf/EdPmqBrc5l6Q5Uu+2TbuhaKbgaCpP2TfAeiNaQPAadxO+CYBRHGUzIDteMAjFspFLDLnKVQ==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "tslib": "^2.2.0" + } + }, + "@azure/core-client": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.6.1.tgz", + "integrity": "sha512-mZ1MSKhZBYoV8GAWceA+PEJFWV2VpdNSpxxcj1wjIAOi00ykRuIQChT99xlQGZWLY3/NApWhSImlFwsmCEs4vA==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-rest-pipeline": "^1.9.1", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.0.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.2.0" + } + }, + "@azure/core-http-compat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-1.3.0.tgz", + "integrity": "sha512-ZN9avruqbQ5TxopzG3ih3KRy52n8OAbitX3fnZT5go4hzu0J+KVPSzkL+Wt3hpJpdG8WIfg1sBD1tWkgUdEpBA==", + "requires": { + "@azure/abort-controller": "^1.0.4", + "@azure/core-client": "^1.3.0", + "@azure/core-rest-pipeline": "^1.3.0" + } + }, + "@azure/core-lro": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.4.0.tgz", + "integrity": "sha512-F65+rYkll1dpw3RGm8/SSiSj+/QkMeYDanzS/QKlM1dmuneVyXbO46C88V1MRHluLGdMP6qfD3vDRYALn0z0tQ==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.2.0" + } + }, + "@azure/core-paging": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.3.0.tgz", + "integrity": "sha512-H6Tg9eBm0brHqLy0OSAGzxIh1t4UL8eZVrSUMJ60Ra9cwq2pOskFqVpz2pYoHDsBY1jZ4V/P8LRGb5D5pmC6rg==", + "requires": { + "tslib": "^2.2.0" + } + }, + "@azure/core-rest-pipeline": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.9.2.tgz", + "integrity": "sha512-8rXI6ircjenaLp+PkOFpo37tQ1PQfztZkfVj97BIF3RPxHAsoVSgkJtu3IK/bUEWcb7HzXSoyBe06M7ODRkRyw==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.0.0", + "@azure/logger": "^1.0.0", + "form-data": "^4.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "tslib": "^2.2.0", + "uuid": "^8.3.0" + } + }, + "@azure/core-tracing": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.1.tgz", + "integrity": "sha512-I5CGMoLtX+pI17ZdiFJZgxMJApsK6jjfm85hpgp3oazCdq5Wxgh4wMr7ge/TTWW1B5WBuvIOI1fMU/FrOAMKrw==", + "requires": { + "tslib": "^2.2.0" + } + }, + "@azure/core-util": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.1.1.tgz", + "integrity": "sha512-A4TBYVQCtHOigFb2ETiiKFDocBoI1Zk2Ui1KpI42aJSIDexF7DHQFpnjonltXAIU/ceH+1fsZAWWgvX6/AKzog==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "tslib": "^2.2.0" + } + }, + "@azure/identity": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-3.0.0.tgz", + "integrity": "sha512-MAwrefZE6T15wJe/tOA6dffdTNCh+S6DOQe2otO6drEEVCHDF0zb+GItlK6kQzD5hPm/YueFCW6sN1q6F4XYuQ==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.4.0", + "@azure/core-rest-pipeline": "^1.1.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.0.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^2.26.0", + "@azure/msal-common": "^7.0.0", + "@azure/msal-node": "^1.10.0", + "events": "^3.0.0", + "jws": "^4.0.0", + "open": "^8.0.0", + "stoppable": "^1.1.0", + "tslib": "^2.2.0", + "uuid": "^8.3.0" + } + }, + "@azure/keyvault-secrets": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@azure/keyvault-secrets/-/keyvault-secrets-4.6.0.tgz", + "integrity": "sha512-MDqsyODCGC2srqLKmO6MFw9WdgLrbPsfCNxgbekHXEd6XKM6KKyBlup5joj96EmdfZnXDFriecAIpj0Dtu81RQ==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.5.0", + "@azure/core-http-compat": "^1.3.0", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.1.1", + "@azure/core-rest-pipeline": "^1.8.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.0.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.2.0" + } + }, + "@azure/logger": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.3.tgz", + "integrity": "sha512-aK4s3Xxjrx3daZr3VylxejK3vG5ExXck5WOHDJ8in/k9AqlfIyFMMT1uG7u8mNjX+QRILTIn0/Xgschfh/dQ9g==", + "requires": { + "tslib": "^2.2.0" + } + }, + "@azure/msal-browser": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-2.30.0.tgz", + "integrity": "sha512-4Y9+rjJiTFP7KEmuq1btmIrBgk0ImNyKsXj6A6NHZALd1X0M6W7L7kxpH6F+d1tEkMv8bYnZdn7IcauXbL8Llw==", + "requires": { + "@azure/msal-common": "^7.6.0" + } + }, + "@azure/msal-common": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-7.6.0.tgz", + "integrity": "sha512-XqfbglUTVLdkHQ8F9UQJtKseRr3sSnr9ysboxtoswvaMVaEfvyLtMoHv9XdKUfOc0qKGzNgRFd9yRjIWVepl6Q==" + }, + "@azure/msal-node": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.14.2.tgz", + "integrity": "sha512-t3whVhhLdZVVeDEtUPD2Wqfa8BDi3EDMnpWp8dbuRW0GhUpikBfs4AQU0Fe6P9zS87n9LpmUTLrIcPEEuzkvfA==", + "requires": { + "@azure/msal-common": "^7.6.0", + "jsonwebtoken": "^8.5.1", + "uuid": "^8.3.0" + } + }, "@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -6006,6 +6672,11 @@ "tslib": "^2.4.0" } }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" + }, "@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", @@ -6104,6 +6775,14 @@ "dev": true, "requires": {} }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -6255,6 +6934,11 @@ "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -6338,6 +7022,11 @@ "ieee754": "^1.2.1" } }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -6404,6 +7093,14 @@ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "compute-scroll-into-view": { "version": "1.0.17", "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz", @@ -6542,6 +7239,11 @@ "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==", "peer": true }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==" + }, "define-properties": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", @@ -6551,6 +7253,11 @@ "object-keys": "^1.1.1" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -6574,6 +7281,14 @@ "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.3.tgz", "integrity": "sha512-Gj9hZN3a07cbR6zviMUBOMPdWxYhbMI+x+WS0NAIu2zFZmbK8ys9R79g+iG9qLnlCwpFoaB+fKy8Pdv470GsPA==" }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "electron-to-chromium": { "version": "1.4.271", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.271.tgz", @@ -6970,6 +7685,11 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -7078,6 +7798,16 @@ "is-callable": "^1.1.3" } }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "formik": { "version": "2.2.9", "resolved": "https://registry.npmjs.org/formik/-/formik-2.2.9.tgz", @@ -7264,6 +7994,25 @@ "react-is": "^16.7.0" } }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -7367,6 +8116,11 @@ "has-tostringtag": "^1.0.0" } }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -7467,6 +8221,14 @@ "call-bind": "^1.0.2" } }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "requires": { + "is-docker": "^2.0.0" + } + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -7538,6 +8300,49 @@ "minimist": "^1.2.0" } }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "dependencies": { + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, "jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -7548,6 +8353,25 @@ "object.assign": "^4.1.3" } }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -7598,12 +8422,47 @@ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "peer": true }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -7642,6 +8501,19 @@ "picomatch": "^2.3.1" } }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -7788,6 +8660,16 @@ "wrappy": "1" } }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -8550,6 +9432,11 @@ "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==" }, + "stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==" + }, "string-convert": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", @@ -8798,6 +9685,11 @@ "which-typed-array": "^1.1.2" } }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/front-end/web-next/package.json b/front-end/web-next/package.json index 85f57766..7a2dafa7 100644 --- a/front-end/web-next/package.json +++ b/front-end/web-next/package.json @@ -12,6 +12,8 @@ }, "dependencies": { "@ant-design/icons": "^4.7.0", + "@azure/identity": "^3.0.0", + "@azure/keyvault-secrets": "^4.6.0", "antd": "^4.23.4", "bootstrap-icons": "^1.9.1", "buffer": "^6.0.3", diff --git a/front-end/web-next/pages/home.js b/front-end/web-next/pages/home.js index 3fb1b056..61103513 100644 --- a/front-end/web-next/pages/home.js +++ b/front-end/web-next/pages/home.js @@ -3,34 +3,36 @@ import style from '../styles/homepage.module.css' import Image from 'next/image' import unitlogo from '../img/unitlogo.png' import { Descriptions, Tabs, Avatar, List, PageHeader, Button, Input, Space } from 'antd'; -import {jwtVerify} from 'jose'; +import { jwtVerify } from 'jose'; const { Search } = Input; - let onSearch = async (event) => { - console.log('hi') - } +let onSearch = async (event) => { + console.log('hi') +} const data = [ { - title: 'Ant Design Title 1', + title: 'Ant Design Title 1', }, { - title: 'Ant Design Title 2', + title: 'Ant Design Title 2', }, { - title: 'Ant Design Title 3', + title: 'Ant Design Title 3', }, { - title: 'Ant Design Title 4', + title: 'Ant Design Title 4', }, - ]; +]; const Home = (props) => { - props = props['data'][0] console.log(props) + let props1 = props['data'][0] + let props2 = props['data2'][0] + return <> 홈페이지 @@ -38,70 +40,70 @@ const Home = (props) => { - ]} + ]} /> -
+
-
소속부대
+
{props2.Unitname || "no data"}
-

충성, 명예, 단결

살아방패 죽어충성

+

{props2.Unitslogan || "no data"}

-
- {props.Rank} {props.Name}
+
+ {props1.Rank} {props1.Name}
정보통신운용장교 - - {props.DoDID} - 정보통신운용장교 - {props.Type} - {props.email} + + {props1.DoDID || "no data"} + {props1.Role || "no data"} + {props1.Type || "no data"} + {props1.email || "no data"} 992-6202 010-3315-1229
-
- - - - 수도방위사령부 방공여단 - 충성, 명예, 단결 살아방패 죽어충성 - - - - ( - - } - title={{item.title}} - description="Ant Design, a design language for background applications, is refined by Ant UED Team" +
+ + + + {props2.Unitname || "no data"} + {props2.Unitslogan || "no data"} + + + + ( + + } + title={{item.title}} + description="Ant Design, a design language for background applications, is refined by Ant UED Team" + /> + + )} /> - - )} - /> - - - Content 3 - - -
+
+ + Content 3 + +
+
@@ -113,10 +115,8 @@ const secret = process.env.JWT_SECRET export async function getServerSideProps(context) { const JWTtoken = context.req.cookies['usercookie']; // => 'value' - console.log(JWTtoken) const { payload } = await jwtVerify(JWTtoken, new TextEncoder().encode(secret)) let id = payload['id'] - console.log(id) const options = { // The method is POST because we are sending data. method: 'GET', @@ -126,11 +126,31 @@ export async function getServerSideProps(context) { 'Authorization': 'Bearer ' + JWTtoken } } -//Fetch data from external API - const res = await fetch(endpoint + id, options) - const data = await res.json() -//Pass data to the page via props - return { props: {data} } + //Fetch data from external API + const res = await fetch(endpoint + id, options) + const data = await res.json() + //Pass data to the page via props + // console.log('hi') + // console.log(data[0]['Unit']) + if (data[0]['Unit']) { + endpoint = backendroot + 'api/unit/get?search=' + const options = { + // The method is POST because we are sending data. + method: 'GET', + // Tell the server we're sending JSON. + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + JWTtoken + } + } + const res2 = await fetch(endpoint + data[0]['Unit'], options) + const data2 = await res2.json() + return { props: { data, data2 } } + + + } + + return { props: { data } } } export default Home; diff --git a/front-end/web-next/pages/index.js b/front-end/web-next/pages/index.js index ba061305..2158ab6f 100644 --- a/front-end/web-next/pages/index.js +++ b/front-end/web-next/pages/index.js @@ -6,9 +6,10 @@ import { Input, Form } from 'antd'; import React, { useState } from 'react'; import { setCookie } from 'cookies-next'; import { useRouter } from 'next/router'; +import { encryptuser, decryptuser } from "../encryption/userencryption" const backendroot = process.env.NEXT_PUBLIC_BACKEND_ROOT - +//let val = encryptuser('a', 'b') export default function Home() { const router = useRouter() const [DoDID, setDoDID] = useState(); @@ -37,7 +38,11 @@ export default function Home() { setCookie('usercookie', result.token) router.push('/home') } else { - setError(result.message) + if (result.message == '승인된 사용자이나 아직 등록되지 않았습니다. 계정 등록 후 이용해주세요.') { + setError('계정 등록 후 이용해주세요.') + } else { + setError(result.message) + } } } return ( diff --git a/front-end/web-next/pages/register.js b/front-end/web-next/pages/register.js index 1cd16c83..2902552b 100644 --- a/front-end/web-next/pages/register.js +++ b/front-end/web-next/pages/register.js @@ -5,6 +5,7 @@ import Link from "next/link" import React, { useState } from 'react'; import { Input, Form } from 'antd'; import { useRouter } from 'next/router'; +import { encryptuser, decryptuser } from "../encryption/userencryption" @@ -13,8 +14,8 @@ const Register = () => { const [Name, setName] = useState(); const [DoDID, setDoDID] = useState(); const [Invcode, setInvcode] = useState(); - const [Password, setPassword] = useState(); - const [ConfPassword, setConfPassword] = useState(); + const [Password, setPassword] = useState(); + const [ConfPassword, setConfPassword] = useState(); const [error, seterror] = useState(''); const [success, setsuccess] = useState(''); @@ -29,72 +30,72 @@ const Register = () => { pic: "https://camo.githubusercontent.com/3c2bd3f35721dc332ebf2b11ace89722c37a0f60b94eac42b2a0462fdeb2d420/68747470733a2f2f63646e2d69636f6e732d706e672e666c617469636f6e2e636f6d2f3531322f363134322f363134323232362e706e67", Invcode: Invcode - } - const JSONdata = JSON.stringify(data) - const options = { - // The method is POST because we are sending data. - method: 'POST', - // Tell the server we're sending JSON. - headers: { - 'Content-Type': 'application/json', - }, - // Body of the request is the JSON data we created above. - body: JSONdata, - } - const response = await fetch(endpoint, options) - const result = await response.json() - console.log(result) - if (result['DoDID']) { - seterror("") - setsuccess("계정이 성공적으로 만들어젔습니다. 가입해주세요!") - } else { - setsuccess("") - seterror(result['message']) - } + } + const JSONdata = JSON.stringify(data) + const options = { + // The method is POST because we are sending data. + method: 'POST', + // Tell the server we're sending JSON. + headers: { + 'Content-Type': 'application/json', + }, + // Body of the request is the JSON data we created above. + body: JSONdata, + } + const response = await fetch(endpoint, options) + const result = await response.json() + console.log(result) + if (result['DoDID']) { + seterror("") + setsuccess("계정이 성공적으로 만들어젔습니다.") + } else { + setsuccess("") + seterror(result['message']) + } } return ( <> - - 회원가입 - - -

회원가입

- - - { setName(event.target.value) }} /> - - - { setDoDID(event.target.value) }} /> - - - { setInvcode(event.target.value) }} /> - - - { setPassword(event.target.value) }} /> - - ({ - validator(_, value) { - if (!value || getFieldValue('비밀번호') === value) { - return Promise.resolve(); - } - return Promise.reject(new Error('비밀번호가 일치하지 않습니다!')); - }, - }),] }> - { setConfPassword(event.target.value) }} /> - -

-
- -

{error}

-

{success}

+ + 회원가입 + + +

회원가입

+ + + { setName(event.target.value) }} /> + + + { setDoDID(event.target.value) }} /> + + + { setInvcode(event.target.value) }} /> + + + { setPassword(event.target.value) }} /> + + ({ + validator(_, value) { + if (!value || getFieldValue('비밀번호') === value) { + return Promise.resolve(); + } + return Promise.reject(new Error('비밀번호가 일치하지 않습니다!')); + }, + }),]}> + { setConfPassword(event.target.value) }} /> + +

+
+ +

{error}

+

{success}

-
- -
- 계정이 있으세요? 로그인

- 비밀번호를 잃어버리셨나요? 비밀번호 찾기 -
-
+
+ +
+ 계정이 있으세요? 로그인

+ 비밀번호를 잃어버리셨나요? 비밀번호 찾기 +
+
) } From 34beb18c0f39c3e82e2872612220fe011c1ef18c Mon Sep 17 00:00:00 2001 From: hyeongmin Kim <113012760+gudmin0526@users.noreply.github.com> Date: Wed, 19 Oct 2022 13:35:47 +0000 Subject: [PATCH 18/48] Feat: Add 'add person' feat in create report screen. --- back-end/controllers/commentControllers.js | 24 +- back-end/package-lock.json | 1943 ++++++++++++++++- .../app/src/apis/report/addCommentApi.js | 16 +- front-end/app/src/components/Profile/index.js | 25 +- .../app/src/components/ReportComment/index.js | 16 +- .../app/src/components/ReportComment/style.js | 10 +- .../app/src/components/ReportContent/style.js | 8 +- .../app/src/components/ReportGroup/index.js | 6 +- .../app/src/components/ReportGroup/style.js | 4 +- .../src/components/ReportListItem/index.js | 67 +- front-end/app/src/navigation/MainNavigator.js | 2 + front-end/app/src/navigation/TopNavigator.js | 1 + .../app/src/screens/LoginScreen/index.js | 26 +- .../app/src/screens/SignUpScreen/index.js | 30 +- front-end/app/src/screens/index.js | 2 + .../report-screens/CreateReportScreen.js | 77 +- .../report-screens/RecdReportScreen.js | 8 +- .../screens/report-screens/ReportScreen.js | 76 +- .../report-screens/SentReportScreen.js | 8 +- .../screens/setting-screens/SettingScreen.js | 2 +- .../screens/setting-screens/SysMgtScreen.js | 2 + .../screens/setting-screens/UnitAddScreen.js | 4 +- .../screens/setting-screens/UnitMgtScreen.js | 4 +- .../screens/setting-screens/UserAddScreen.js | 2 +- .../screens/setting-screens/UserMgtScreen.js | 2 +- .../setting-screens/UserUpdateScreen.js | 4 +- 26 files changed, 2194 insertions(+), 175 deletions(-) diff --git a/back-end/controllers/commentControllers.js b/back-end/controllers/commentControllers.js index 51cb9e6c..7350fbf9 100644 --- a/back-end/controllers/commentControllers.js +++ b/back-end/controllers/commentControllers.js @@ -6,11 +6,7 @@ const ReportM = require("../models/reportModel"); //@route POST /api/comment //@access Protected const addComment = asyncHandler(async (req, res) => { - const { - Type, - Content, - Title - } = req.body; + const { Type, Content, Title } = req.body; if (!Type || !Content || !Title) { res.status(400); @@ -19,7 +15,9 @@ const addComment = asyncHandler(async (req, res) => { User = req.user._id; - report = await Report.find({ Title: { $eq: keyword }}).find({Unit: {$eq: req.user.Unit}}); + report = await Report.find({ Title: { $eq: keyword } }).find({ + Unit: { $eq: req.user.Unit }, + }); Report = report._id; @@ -27,18 +25,20 @@ const addComment = asyncHandler(async (req, res) => { User, Type, Content, - report + report, }); const editReport = await ReportM.findByIdAndUpdate( - report._id, { + report._id, + { $push: { - Comments: comment + Comments: comment, }, - }, { + }, + { new: true, } - ) + ); if (editReport && editUnit && editUser) { res.status(201).send(comment); @@ -49,5 +49,5 @@ const addComment = asyncHandler(async (req, res) => { }); module.exports = { - addComment + addComment, }; diff --git a/back-end/package-lock.json b/back-end/package-lock.json index bf68b3e4..3e8c8421 100644 --- a/back-end/package-lock.json +++ b/back-end/package-lock.json @@ -1,8 +1,1943 @@ { "name": "roksrs", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "roksrs", + "version": "1.0.0", + "dependencies": { + "bcryptjs": "^2.4.3", + "classificator": "^0.3.4", + "colors": "^1.4.0", + "cors": "^2.8.5", + "dotenv": "^9.0.2", + "express": "^4.17.1", + "express-async-handler": "^1.1.4", + "jsonwebtoken": "^8.5.1", + "mongoose": "^5.12.9", + "nodemon": "^2.0.7", + "nodepapago": "^3.1.1", + "socket.io": "^4.1.2", + "wink-pos-tagger": "^2.2.2" + }, + "devDependencies": { + "swagger-jsdoc": "^6.2.5", + "swagger-ui-express": "^4.5.0" + } + }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", + "integrity": "sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==", + "dev": true, + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.6", + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0" + } + }, + "node_modules/@apidevtools/openapi-schemas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", + "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@apidevtools/swagger-methods": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", + "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", + "dev": true + }, + "node_modules/@apidevtools/swagger-parser": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.2.tgz", + "integrity": "sha512-JFxcEyp8RlNHgBCE98nwuTkZT6eNFPc1aosWV6wPcQph72TSEEu1k3baJD4/x1qznU+JiDdz8F5pTwabZh+Dhg==", + "dev": true, + "dependencies": { + "@apidevtools/json-schema-ref-parser": "^9.0.6", + "@apidevtools/openapi-schemas": "^2.0.4", + "@apidevtools/swagger-methods": "^3.0.2", + "@jsdevtools/ono": "^7.1.3", + "call-me-maybe": "^1.0.1", + "z-schema": "^4.2.3" + }, + "peerDependencies": { + "openapi-types": ">=7" + } + }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", + "dev": true + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, + "node_modules/@types/bson": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.5.tgz", + "integrity": "sha512-vVLwMUqhYJSQ/WKcE60eFqcyuWse5fGH+NMAXHuKrUAPoryq3ATxk5o4bgYNtg5aOM4APVg7Hnb3ASqUYG0PKg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/mongodb": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz", + "integrity": "sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ==", + "dependencies": { + "@types/bson": "*", + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "18.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.2.tgz", + "integrity": "sha512-cRMwIgdDN43GO4xMWAfJAecYn8wV4JbsOGHNfNUIDiuYkUYAR5ec4Rj7IO2SAhFPEfpPtLtUTbbny/TCT7aDwA==" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, + "node_modules/body-parser": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bson": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw==", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/classificator": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/classificator/-/classificator-0.3.4.tgz", + "integrity": "sha512-H0ZCdZj1oEKr7jx//k8laegv8njniDWDPRE72HQ3250ow9I1g0ueO6n/RjzZPC9AMwfs3IoOCXfyMOLSonqkmg==", + "dependencies": { + "decimal.js": "^10.0.0" + }, + "engines": { + "node": ">=5.0.0" + } + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", + "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decimal.js": { + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.2.tgz", + "integrity": "sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==" + }, + "node_modules/denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz", + "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", + "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.0", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.10.3", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express-async-handler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/express-async-handler/-/express-async-handler-1.2.0.tgz", + "integrity": "sha512-rCSVtPXRmQSW8rmik/AIb2P0op6l7r1fMW538yyvTMltCO4xQEWMmobfrIxN2V1/mVrgxB8Az3reYF6yUZw37w==" + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/kareem": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz", + "integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ==" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "dev": true + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mongodb": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", + "integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==", + "dependencies": { + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "optional-require": "^1.1.8", + "safe-buffer": "^5.1.2" + }, + "engines": { + "node": ">=4" + }, + "optionalDependencies": { + "saslprep": "^1.0.0" + }, + "peerDependenciesMeta": { + "aws4": { + "optional": true + }, + "bson-ext": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "mongodb-extjson": { + "optional": true + }, + "snappy": { + "optional": true + } + } + }, + "node_modules/mongodb/node_modules/optional-require": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz", + "integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==", + "dependencies": { + "require-at": "^1.0.6" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mongoose": { + "version": "5.13.15", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.15.tgz", + "integrity": "sha512-cxp1Gbb8yUWkaEbajdhspSaKzAvsIvOtRlYD87GN/P2QEUhpd6bIvebi36T6M0tIVAMauNaK9SPA055N3PwF8Q==", + "dependencies": { + "@types/bson": "1.x || 4.0.x", + "@types/mongodb": "^3.5.27", + "bson": "^1.1.4", + "kareem": "2.3.2", + "mongodb": "3.7.3", + "mongoose-legacy-pluralize": "1.0.2", + "mpath": "0.8.4", + "mquery": "3.2.5", + "ms": "2.1.2", + "optional-require": "1.0.x", + "regexp-clone": "1.0.0", + "safe-buffer": "5.2.1", + "sift": "13.5.2", + "sliced": "1.0.1" + }, + "engines": { + "node": ">=4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mongoose-legacy-pluralize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", + "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==", + "peerDependencies": { + "mongoose": "*" + } + }, + "node_modules/mongoose/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/mpath": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.4.tgz", + "integrity": "sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.5.tgz", + "integrity": "sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A==", + "dependencies": { + "bluebird": "3.5.1", + "debug": "3.1.0", + "regexp-clone": "^1.0.0", + "safe-buffer": "5.1.2", + "sliced": "1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/mquery/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nodemon": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/nodepapago": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/nodepapago/-/nodepapago-3.1.1.tgz", + "integrity": "sha512-67QjA2ueackA6/ijGNMn9xVHhJbg7gPE884nHmD5pJASZES3zzMVNrAtLDoRkkTLfqX9oL1C2WlXTowtqkHmag==", + "dependencies": { + "axios": "^0.21.4", + "uuid": "^8.3.2" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optional-require": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", + "integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + }, + "node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regexp-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", + "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==" + }, + "node_modules/require-at": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", + "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sift": { + "version": "13.5.2", + "resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz", + "integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA==" + }, + "node_modules/simple-update-notifier": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", + "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==" + }, + "node_modules/socket.io": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.2.tgz", + "integrity": "sha512-6fCnk4ARMPZN448+SQcnn1u8OHUC72puJcNtSgg2xS34Cu7br1gQ09YKkO1PFfDn/wyUE9ZgMAwosJed003+NQ==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.2.0", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==" + }, + "node_modules/socket.io-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/swagger-jsdoc": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.5.tgz", + "integrity": "sha512-l+cdsKS2y+QDhrH1TJSUiE0y9XKuf5xaGSatjf0hR/wjTlMpO8WfubBK9d/nASdbHPMtj9iJZLBH2ogBEhL7Sw==", + "dev": true, + "dependencies": { + "commander": "6.2.0", + "doctrine": "3.0.0", + "glob": "7.1.6", + "lodash.mergewith": "^4.6.2", + "swagger-parser": "10.0.2", + "yaml": "2.0.0-1" + }, + "bin": { + "swagger-jsdoc": "bin/swagger-jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/swagger-parser": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.2.tgz", + "integrity": "sha512-9jHkHM+QXyLGFLk1DkXBwV+4HyNm0Za3b8/zk/+mjr8jgOSiqm3FOTHBSDsBjtn9scdL+8eWcHdupp2NLM8tDw==", + "dev": true, + "dependencies": { + "@apidevtools/swagger-parser": "10.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/swagger-ui-dist": { + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.14.2.tgz", + "integrity": "sha512-kOIU7Ts3TrXDLb3/c9jRe4qGp8O3bRT19FFJA8wJfrRFkcK/4atPn3krhtBVJ57ZkNNofworXHxuYwmaisXBdg==", + "dev": true + }, + "node_modules/swagger-ui-express": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.5.0.tgz", + "integrity": "sha512-DHk3zFvsxrkcnurGvQlAcLuTDacAVN1JHKDgcba/gr2NFRE4HGwP1YeHIXMiGznkWR4AeS7X5vEblNn4QljuNA==", + "dev": true, + "dependencies": { + "swagger-ui-dist": ">=4.11.0" + }, + "engines": { + "node": ">= v0.10.32" + }, + "peerDependencies": { + "express": ">=4.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/wink-helpers": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wink-helpers/-/wink-helpers-2.0.0.tgz", + "integrity": "sha512-I/ZzXrHcNRXuoeFJmp2vMVqDI6UCK02Tds1WP4kSGAmx520gjL1BObVzF7d2ps24tyHIly9ngdB2jwhlFUjPvg==" + }, + "node_modules/wink-lemmatizer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/wink-lemmatizer/-/wink-lemmatizer-3.0.2.tgz", + "integrity": "sha512-0G572wdcujnRfpjSKs2lDXjA2+8APzkQu+gsREzzOjqg39C1ACE912veMwx2onlbYfUifsZRVaLZUOXjsHFVzA==", + "dependencies": { + "wink-lexicon": "^2.1.2", + "wink-porter2-stemmer": "^2.0.0" + } + }, + "node_modules/wink-lexicon": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/wink-lexicon/-/wink-lexicon-2.1.2.tgz", + "integrity": "sha512-LUIVIKNIURMHN38leZXWP+ZE0b1jWUdGDHfgV6kmPSHy2AqwHS/n8xGADRsfJxJamLb6BwQY713/w2XnWYk/HQ==" + }, + "node_modules/wink-porter2-stemmer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wink-porter2-stemmer/-/wink-porter2-stemmer-2.0.1.tgz", + "integrity": "sha512-0g+RkkqhRXFmSpJQStVXW5N/WsshWpJXsoDRW7DwVkGI2uDT6IBCoq3xdH5p6IHLaC6ygk7RWUsUx4alKxoagQ==" + }, + "node_modules/wink-pos-tagger": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/wink-pos-tagger/-/wink-pos-tagger-2.2.2.tgz", + "integrity": "sha512-+bhkwqwwChqWR75ksFKVJZQagwu404UmnvFjxr+OWZ02/ZJAv19N/iqDpMeYRQRxatk5N+W9pXIKEDJsVrzGyw==", + "dependencies": { + "wink-helpers": "^2.0.0", + "wink-lemmatizer": "^3.0.1", + "wink-lexicon": "^2.1.1", + "wink-porter2-stemmer": "^2.0.0", + "wink-tokenizer": "^5.2.1" + } + }, + "node_modules/wink-tokenizer": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/wink-tokenizer/-/wink-tokenizer-5.3.0.tgz", + "integrity": "sha512-O/yAw0g3FmSgeeQuYAJJfP7fVPB4A6ay0018qASh79aWmIOyPYy4j4r9EQT8xBjicja6lCLvgRVAybmEBaATQA==", + "dependencies": { + "emoji-regex": "^9.0.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yaml": { + "version": "2.0.0-1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz", + "integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/z-schema": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-4.2.4.tgz", + "integrity": "sha512-YvBeW5RGNeNzKOUJs3rTL4+9rpcvHXt5I051FJbOcitV8bl40pEfcG0Q+dWSwS0/BIYrMZ/9HHoqLllMkFhD0w==", + "dev": true, + "dependencies": { + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.6.0" + }, + "bin": { + "z-schema": "bin/z-schema" + }, + "engines": { + "node": ">=6.0.0" + }, + "optionalDependencies": { + "commander": "^2.7.1" + } + }, + "node_modules/z-schema/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "optional": true + } + }, "dependencies": { "@apidevtools/json-schema-ref-parser": { "version": "9.0.9", @@ -866,7 +2801,8 @@ "mongoose-legacy-pluralize": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", - "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" + "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==", + "requires": {} }, "mpath": { "version": "0.8.4", @@ -1452,7 +3388,8 @@ "ws": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==" + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "requires": {} }, "yaml": { "version": "2.0.0-1", diff --git a/front-end/app/src/apis/report/addCommentApi.js b/front-end/app/src/apis/report/addCommentApi.js index f678a3b2..a3ada46d 100644 --- a/front-end/app/src/apis/report/addCommentApi.js +++ b/front-end/app/src/apis/report/addCommentApi.js @@ -1,19 +1,23 @@ import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' -const addCommentApi = async ({ Type, Content }) => { +const addCommentApi = async ({ Type, Content, Title, _id }) => { try { - const res = await fetch(URL, { + const res = await fetch(URL + '/api/comment', { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, }, - body: { - Type, - Content, - }, + body: JSON.stringify({ + Type: Type, + Content: Content, + Title: Title, + }), + user: JSON.stringify({ + _id: _id, + }), }) return res.json() } catch (error) { diff --git a/front-end/app/src/components/Profile/index.js b/front-end/app/src/components/Profile/index.js index 0a0778d7..f5e1eba0 100644 --- a/front-end/app/src/components/Profile/index.js +++ b/front-end/app/src/components/Profile/index.js @@ -3,29 +3,30 @@ import { Avatar } from 'react-native-paper' import { useNunitoFonts } from '../../hooks/useNunitoFonts' import { styles } from './style' -export function Profile({ - name = '병장 김형민', - position = '본부중대 통신', - size = 45, - src = require('../../assets/images/avatar.png'), - date, - right, -}) { +export function Profile( + { + name = '병장 김형민', + position = '본부중대 통신', + size = 45, + src = require('../../assets/images/avatar.png'), + }, + props +) { let [fontsLoaded] = useNunitoFonts() return ( - + {name} {position} - {date && ( + {props.date && ( - {date} + {props.date} )} - {right && right} + {props.right} ) } diff --git a/front-end/app/src/components/ReportComment/index.js b/front-end/app/src/components/ReportComment/index.js index 6035267e..15b98c97 100644 --- a/front-end/app/src/components/ReportComment/index.js +++ b/front-end/app/src/components/ReportComment/index.js @@ -1,13 +1,17 @@ -import { View } from 'react-native' -import { Paragraph } from 'react-native-paper' +import { View, Text } from 'react-native' +import { Paragraph, Colors } from 'react-native-paper' import { useNunitoFonts } from '../../hooks/useNunitoFonts' import moment from 'moment' import { styles } from './style' import { Profile } from '../Profile' -export function ReportComment({ Name, position, Content }) { +export function ReportComment({ Name, position, Content, Type }) { let [fontsLoaded] = useNunitoFonts() + const type = + Type === 'emergency' ? '[긴급]' : Type === 'order' ? '[지시]' : '[보고]' + const color = + Type === 'emergency' ? 'red' : Type === 'order' ? Colors.amber700 : 'green' return ( - {Content} - + + {type} + {Content} + ) } diff --git a/front-end/app/src/components/ReportComment/style.js b/front-end/app/src/components/ReportComment/style.js index 3b5eae03..94cab80c 100644 --- a/front-end/app/src/components/ReportComment/style.js +++ b/front-end/app/src/components/ReportComment/style.js @@ -6,7 +6,8 @@ export const styles = StyleSheet.create({ width: '97%', borderBottomWidth: 1, borderColor: Colors.grey400, - paddingVertical: 8, + paddingTop: 5, + paddingBottom: 3, paddingLeft: 3, alignSelf: 'center', }, @@ -21,9 +22,12 @@ export const styles = StyleSheet.create({ fontFamily: 'NunitoSans_300Light', color: Colors.grey900, }, + type: { + fontFamily: 'NunitoSans_600SemiBold', + fontSize: 13, + marginRight: 3, + }, paragraph: { - width: '100%', - marginTop: 5, fontFamily: 'NunitoSans_400Regular', fontSize: 13, }, diff --git a/front-end/app/src/components/ReportContent/style.js b/front-end/app/src/components/ReportContent/style.js index c6dbd205..f0d87bcf 100644 --- a/front-end/app/src/components/ReportContent/style.js +++ b/front-end/app/src/components/ReportContent/style.js @@ -44,14 +44,14 @@ export const styles = StyleSheet.create({ marginTop: 10, }, seqText: { - marginTop: 5, - fontFamily: 'NunitoSans_600SemiBold', - fontSize: 11, + paddingTop: 2, + fontFamily: 'NunitoSans_400Regular', + fontSize: 12, color: Colors.grey800, }, buttonView: { marginTop: 10, - marginRight: 3, + marginRight: 2, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', diff --git a/front-end/app/src/components/ReportGroup/index.js b/front-end/app/src/components/ReportGroup/index.js index 671ba17e..36b3c850 100644 --- a/front-end/app/src/components/ReportGroup/index.js +++ b/front-end/app/src/components/ReportGroup/index.js @@ -10,7 +10,11 @@ const ItemSeparator = () => ( ) diff --git a/front-end/app/src/components/ReportGroup/style.js b/front-end/app/src/components/ReportGroup/style.js index 197bdd7b..18d22734 100644 --- a/front-end/app/src/components/ReportGroup/style.js +++ b/front-end/app/src/components/ReportGroup/style.js @@ -6,13 +6,13 @@ export const styles = StyleSheet.create({ justifyContent: 'center', }, view: { - borderWidth: 1, borderRadius: 6, - borderColor: Colors.grey700, alignItems: 'center', paddingVertical: 3, width: 75, marginBottom: 2, + backgroundColor: Colors.grey200, + elevation: 3, }, image: { marginBottom: 5, diff --git a/front-end/app/src/components/ReportListItem/index.js b/front-end/app/src/components/ReportListItem/index.js index 0b0ed24b..ca994fb5 100644 --- a/front-end/app/src/components/ReportListItem/index.js +++ b/front-end/app/src/components/ReportListItem/index.js @@ -5,7 +5,6 @@ import { useNunitoFonts } from '../../hooks/useNunitoFonts' import { useNavigation } from '@react-navigation/native' import { styles } from './style' -// prettier-ignore export function ReportListItem(props) { const { Title, isEnd, Content, severity, date, Type } = props console.log(props) @@ -15,39 +14,47 @@ export function ReportListItem(props) { const navigation = useNavigation() const goReportScreen = () => { - navigation.navigate('ReportScreen', { - Title, - isEnd, - Content, - severity, - date, - Type, + navigation.navigate('ReportNavigator', { + screen: 'ReportScreen', + params: { + Title, + isEnd, + Content, + severity, + date, + Type, + }, }) } return ( - - - - {Title} - {isEnd ? '[종결]' : '[미종결]'} - - - {Content} - - - 중요도: - {severity} - - {date} - - - + + + + {Title} + + {isEnd ? '[종결]' : '[미종결]'} + + + + {Content} + + + 중요도: + {severity} + {date} + + ) } diff --git a/front-end/app/src/navigation/MainNavigator.js b/front-end/app/src/navigation/MainNavigator.js index f59f2a01..547c5962 100644 --- a/front-end/app/src/navigation/MainNavigator.js +++ b/front-end/app/src/navigation/MainNavigator.js @@ -3,6 +3,7 @@ import { createStackNavigator } from '@react-navigation/stack' import TabNavigator from './TabNavigator' import ReportNavigator from './ReportNavigator' import ChatNavigator from './ChatNavigator' +import TopNavigator from './TopNavigator' import SettingNavigator from './SettingNavigator' import { LoginScreen, SignUpScreen } from '../screens' @@ -19,6 +20,7 @@ export default function MainNavigator() { component={SignUpScreen} options={{ title: '사용신청', headerShown: true }} /> + diff --git a/front-end/app/src/navigation/TopNavigator.js b/front-end/app/src/navigation/TopNavigator.js index 141fd633..8e077b5f 100644 --- a/front-end/app/src/navigation/TopNavigator.js +++ b/front-end/app/src/navigation/TopNavigator.js @@ -1,5 +1,6 @@ import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs' import { Colors } from 'react-native-paper' +import ReportNavigator from './ReportNavigator' import { RecdReportScreen, SentReportScreen } from '../screens' const Tab = createMaterialTopTabNavigator() diff --git a/front-end/app/src/screens/LoginScreen/index.js b/front-end/app/src/screens/LoginScreen/index.js index 0e3d11fe..b083aeaf 100644 --- a/front-end/app/src/screens/LoginScreen/index.js +++ b/front-end/app/src/screens/LoginScreen/index.js @@ -1,4 +1,4 @@ -import React, { useState, useCallback, useRef, useMemo } from 'react' +import React, { useState, useCallback } from 'react' import { useRecoilState } from 'recoil' import { userState } from '../../states/userState' //prettier-ignore @@ -10,7 +10,7 @@ import { styles } from './style' import { useNunitoFonts } from '../../hooks/useNunitoFonts' import { GuideText } from '../../components/GuideText' import AppLoading from 'expo-app-loading' -import loginApi from '../../apis/loginApi' +import loginApi from '../../apis/sign/loginApi' export function LoginScreen() { const [userMe, setUserMe] = useRecoilState(userState) @@ -28,7 +28,6 @@ export function LoginScreen() { ...res, token: null, }) - Alert.alert(`${userMe.Name}님, 환영합니다.`) cb() } else { Alert.alert(res.message) @@ -55,19 +54,6 @@ export function LoginScreen() { return } - const ref_input = useMemo([], []) - ref_input[0] = useRef(null) - ref_input[1] = useRef(null) - - const onFocusNext = (index) => { - if (ref_input[index + 1] && index < ref_input.length - 1) { - ref_input[index + 1].current?.focus() - } - if (ref_input[index + 1] && index == ref_input.length - 1) { - ref_input[index].current?.blur() - } - } - return ( @@ -83,10 +69,6 @@ export function LoginScreen() { activeUnderlineColor="#008275" style={styles.loginTextInput} onChangeText={(DoDID) => setDoDID(DoDID)} - ref={ref_input[0]} - onSubmitEditing={() => { - onFocusNext(0) - }} /> @@ -104,10 +86,6 @@ export function LoginScreen() { } style={styles.loginTextInput} onChangeText={(password) => setPassword(password)} - ref={ref_input[1]} - onSubmitEditing={() => { - onFocusNext(1) - }} /> diff --git a/front-end/app/src/screens/SignUpScreen/index.js b/front-end/app/src/screens/SignUpScreen/index.js index d32e4362..00ad332a 100644 --- a/front-end/app/src/screens/SignUpScreen/index.js +++ b/front-end/app/src/screens/SignUpScreen/index.js @@ -1,4 +1,4 @@ -import React, { useState, useCallback, useMemo, useRef } from 'react' +import React, { useState, useCallback } from 'react' import { TextInput } from 'react-native-paper' // prettier-ignore import { View ,SafeAreaView, TouchableOpacity, ScrollView, Text, Alert } from 'react-native' @@ -7,7 +7,7 @@ import { useNavigation } from '@react-navigation/native' import { GuideText } from '../../components/GuideText' import RankItems from '../../data/ranks' import DropDownPicker from 'react-native-dropdown-picker' -import registerApi from '../../apis/registerApi' +import registerApi from '../../apis/sign/registerApi' import { Colors } from 'react-native-paper' const checkPasswordMatch = (password, confirmPassword) => { @@ -41,20 +41,6 @@ export function SignUpScreen() { const [Name, setName] = useState('') const [Invcode, setInvcode] = useState('') - const ref_input = useMemo([], []) - for (let i = 0; i < 6; i++) { - ref_input[i] = useRef(null) - } - - const onFocusNext = (index) => { - if (ref_input[index + 1] && index < ref_input.length - 1) { - ref_input[index + 1].current?.focus() - } - if (ref_input[index + 1] && index == ref_input.length - 1) { - ref_input[index].current?.blur() - } - } - return ( setName(Name)} style={styles.signUpTextInput} - ref={ref_input[0]} - onSubmitEditing={() => onFocusNext[0]} /> @@ -99,8 +83,6 @@ export function SignUpScreen() { activeUnderlineColor="#008275" onChangeText={(DoDID) => setDoDID(DoDID)} style={styles.signUpTextInput} - ref={ref_input[1]} - onSubmitEditing={() => onFocusNext[1]} /> @@ -111,8 +93,6 @@ export function SignUpScreen() { activeUnderlineColor="#008275" onChangeText={(password) => setPassword(password)} style={styles.signUpTextInput} - ref={ref_input[2]} - onSubmitEditing={() => onFocusNext[2]} /> @@ -125,8 +105,6 @@ export function SignUpScreen() { setConfirmPassword(confirmPassword) } style={styles.signUpTextInput} - ref={ref_input[3]} - onSubmitEditing={() => onFocusNext[3]} /> setEmail(email)} style={styles.signUpTextInput} - ref={ref_input[4]} - onSubmitEditing={() => onFocusNext[4]} /> @@ -151,8 +127,6 @@ export function SignUpScreen() { activeUnderlineColor="#008275" onChangeText={(Invcode) => setInvcode(Invcode)} style={styles.signUpTextInput} - ref={ref_input[5]} - onSubmitEditing={() => onFocusNext[5]} /> diff --git a/front-end/app/src/screens/index.js b/front-end/app/src/screens/index.js index ce3a7d66..ff6e30e3 100644 --- a/front-end/app/src/screens/index.js +++ b/front-end/app/src/screens/index.js @@ -11,4 +11,6 @@ export * from './report-screens/ReportScreen' export * from './report-screens/SentReportScreen' export * from './chat-screens/ChatListScreen' export * from './chat-screens/ChatRoomScreen' +export * from './LoginScreen' +export * from './SignUpScreen' export * from './OrgChartScreen' diff --git a/front-end/app/src/screens/report-screens/CreateReportScreen.js b/front-end/app/src/screens/report-screens/CreateReportScreen.js index 27242be2..a6b1a9f3 100644 --- a/front-end/app/src/screens/report-screens/CreateReportScreen.js +++ b/front-end/app/src/screens/report-screens/CreateReportScreen.js @@ -1,24 +1,18 @@ import React, { useState } from 'react' // prettier-ignore import { SafeAreaView, View, StyleSheet, ScrollView } from 'react-native' -import { Colors, Searchbar, Text, Avatar, TextInput } from 'react-native-paper' +import { Colors, TextInput, IconButton } from 'react-native-paper' import { useNunitoFonts } from '../../hooks/useNunitoFonts' import DropDownPicker from 'react-native-dropdown-picker' import { ReportGroup } from '../../components/ReportGroup' import { MyButton } from '../../components/MyButton' import { useNavigation } from '@react-navigation/native' import { Profile } from '../../components/Profile' -import searchUserApi from '../../apis/searchUserApi' +import searchUserApi from '../../apis/user/searchUserApi' import DATA from '../../data/procData' import { window } from '../../constants/layout' export function CreateReportScreen() { - const fetchUserHandler = async (query) => { - const res = await searchUserApi(query) - console.log(res) - return res - } - let [fontsLoaded] = useNunitoFonts() const navigation = useNavigation() @@ -26,7 +20,15 @@ export function CreateReportScreen() { const [query, setQuery] = useState('') const [addedUser, setAddedUser] = useState([]) - console.log(addedUser) + const onRemove = (_id) => { + setAddedUser(addedUser.filter((user) => user._id !== _id)) + } + + const fetchUserHandler = async (query) => { + const res = await searchUserApi(query) + console.log(res) + setAddedUser([...addedUser, res]) + } const [typeOpen, setTypeOpen] = useState(false) const [type, setType] = useState('') @@ -46,6 +48,8 @@ export function CreateReportScreen() { const [title, setTitle] = useState('') const [text, setText] = useState('') + console.log(addedUser) + return ( setQuery(query)} - onSubmitEditing={() => - setAddedUser([...addedUser, fetchUserHandler(query)]) - } - onIconPress={() => - setAddedUser([...addedUser, fetchUserHandler(query)]) + right={ + fetchUserHandler(query)} + /> } + onSubmitEditing={() => fetchUserHandler(query)} activeUnderlineColor="#008275" /> - - {addedUser.map((user, idx) => ( + + {addedUser.map((user) => ( onRemove(user._id)} + /> + } /> ))} @@ -151,12 +173,16 @@ const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: 'white', - paddingBottom: 50, + paddingBottom: 20, }, view: { width: '100%', alignItems: 'center', }, + scrollView: { + width: '85%', + marginBottom: (15 / 812) * window.height, + }, dropDown: { width: '100%', backgroundColor: 'white', @@ -171,4 +197,17 @@ const styles = StyleSheet.create({ backgroundColor: 'white', marginBottom: (30 / 812) * window.height, }, + profile: { + marginRight: 10, + backgroundColor: Colors.grey200, + paddingLeft: 5, + borderRadius: 8, + elevation: 3, + flexDirection: 'row', + alignItems: 'center', + }, + icon: { + marginLeft: 5, + backgroundColor: Colors.grey200, + }, }) diff --git a/front-end/app/src/screens/report-screens/RecdReportScreen.js b/front-end/app/src/screens/report-screens/RecdReportScreen.js index 21832c49..74bb317a 100644 --- a/front-end/app/src/screens/report-screens/RecdReportScreen.js +++ b/front-end/app/src/screens/report-screens/RecdReportScreen.js @@ -5,7 +5,7 @@ import { SafeAreaView, StyleSheet, ScrollView } from 'react-native' import { Colors, FAB } from 'react-native-paper' import { useNavigation } from '@react-navigation/native' import moment from 'moment' -import fetchReportApi from '../../apis/fetchReportApi' +import fetchReportApi from '../../apis/report/fetchReportApi' const { Title, isEnd, Content, severity, date, Type } = { Title: '3초소 거수자 발견', @@ -45,7 +45,11 @@ export function RecdReportScreen() { navigation.navigate('CreateReportScreen')} + onPress={() => + navigation.navigate('ReportNavigator', { + screen: 'CreateReportScreen', + }) + } style={styles.fab} color="white" /> diff --git a/front-end/app/src/screens/report-screens/ReportScreen.js b/front-end/app/src/screens/report-screens/ReportScreen.js index 13049a8c..a673e2e6 100644 --- a/front-end/app/src/screens/report-screens/ReportScreen.js +++ b/front-end/app/src/screens/report-screens/ReportScreen.js @@ -1,16 +1,19 @@ import React, { useState } from 'react' +//prettier-ignore import { SafeAreaView, StyleSheet, View, FlatList, Text } from 'react-native' import { TextInput } from 'react-native-paper' +import DropDownPicker from 'react-native-dropdown-picker' import { ReportHeader } from '../../components/ReportHeader' import { ReportContent } from '../../components/ReportContent' import { ReportComment } from '../../components/ReportComment' import { Colors } from 'react-native-paper' import { useRecoilState } from 'recoil' import { userState } from '../../states/userState' -import addCommentApi from '../../apis/addCommentApi' +import addCommentApi from '../../apis/report/addCommentApi' -const addCommentHandler = async ({ Type, Content, Title }) => { - const res = await addCommentApi({ Type, Content, Title }) +const addCommentHandler = async ({ Type, Content, Title, _id }) => { + const res = await addCommentApi({ Type, Content, Title, _id }) + console.log(res) } export function ReportScreen({ route }) { @@ -21,6 +24,14 @@ export function ReportScreen({ route }) { const [comment, setComment] = useState('') const [comments, setComments] = useState([]) + const [open, setOpen] = useState(false) + const [commentType, setCommentType] = useState('') + const [typeItem, setTypeItem] = useState([ + { label: '보고', value: 'report' }, + { label: '지시', value: 'order' }, + { label: '긴급', value: 'emergency' }, + ]) + const ListHeaderComponent = () => ( ) } @@ -63,7 +75,23 @@ export function ReportScreen({ route }) { showsVerticalScrollIndicator={false} /> - + + { setComments([ @@ -85,9 +116,15 @@ export function ReportScreen({ route }) { Name: userMe.Name, position: userMe.Position, Content: comment, + Type: commentType, }, ]) - addCommentHandler({ Title, Type, Content: comment }) + addCommentHandler({ + Title, + Type: commentType, + Content: comment, + _id: userMe._id, + }) setComment('') }} /> @@ -103,18 +140,31 @@ const styles = StyleSheet.create({ flex: 1, backgroundColor: Colors.white, alignItems: 'center', - paddingBottom: 50, + paddingBottom: 60, }, - view: { + commentView: { bottom: 0, position: 'absolute', - width: '100%', - alignItems: 'center', + width: '99%', + justifyContent: 'center', + flexDirection: 'row', }, commentInput: { - paddingTop: 5, - width: '96%', + paddingTop: 10, + width: '82%', backgroundColor: Colors.grey100, elevation: 4, + marginLeft: 3, + }, + dropDown: { + backgroundColor: Colors.red300, + borderWidth: 0, + borderRadius: 5, + elevation: 4, + }, + dropDownText: { + color: 'white', + fontSize: 14, + textAlign: 'center', }, }) diff --git a/front-end/app/src/screens/report-screens/SentReportScreen.js b/front-end/app/src/screens/report-screens/SentReportScreen.js index a297c762..88b58880 100644 --- a/front-end/app/src/screens/report-screens/SentReportScreen.js +++ b/front-end/app/src/screens/report-screens/SentReportScreen.js @@ -5,7 +5,7 @@ import { SafeAreaView, StyleSheet, ScrollView } from 'react-native' import { Colors, FAB } from 'react-native-paper' import { useNavigation } from '@react-navigation/native' import moment from 'moment' -import fetchReportApi from '../../apis/fetchReportApi' +import fetchReportApi from '../../apis/report/fetchReportApi' const { Title, isEnd, Content, severity, date, Type } = { Title: '3초소 거수자 발견', @@ -45,7 +45,11 @@ export function SentReportScreen() { navigation.navigate('CreateReportScreen')} + onPress={() => + navigation.navigate('ReportNavigator', { + screen: 'CreateReportScreen', + }) + } style={styles.fab} color="white" /> diff --git a/front-end/app/src/screens/setting-screens/SettingScreen.js b/front-end/app/src/screens/setting-screens/SettingScreen.js index e7203e94..0c1664a0 100644 --- a/front-end/app/src/screens/setting-screens/SettingScreen.js +++ b/front-end/app/src/screens/setting-screens/SettingScreen.js @@ -6,7 +6,7 @@ import { SafeAreaView, StyleSheet, ScrollView, Switch, Alert } from 'react-nativ import { List, Colors } from 'react-native-paper' import { useNavigation } from '@react-navigation/native' import { useNunitoFonts } from '../../hooks/useNunitoFonts' -import logoutApi from '../../apis/logoutApi' +import logoutApi from '../../apis/sign/logoutApi' export function SettingScreen() { const [userMe, setUserMe] = useRecoilState(userState) diff --git a/front-end/app/src/screens/setting-screens/SysMgtScreen.js b/front-end/app/src/screens/setting-screens/SysMgtScreen.js index e4638b3e..94dbfff0 100644 --- a/front-end/app/src/screens/setting-screens/SysMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/SysMgtScreen.js @@ -13,6 +13,8 @@ import DATA from '../../data/procData' // 1. Modal이 나을듯 // delete의 경우 button을 통해? + + export function SysMgtScreen() { return ( diff --git a/front-end/app/src/screens/setting-screens/UnitAddScreen.js b/front-end/app/src/screens/setting-screens/UnitAddScreen.js index fa9040d0..3a31fb65 100644 --- a/front-end/app/src/screens/setting-screens/UnitAddScreen.js +++ b/front-end/app/src/screens/setting-screens/UnitAddScreen.js @@ -3,7 +3,7 @@ import { SafeAreaView, View, StyleSheet, Alert } from 'react-native' import { TextInput } from 'react-native-paper' import { ImagePicker } from '../../components/ImagePicker' import { window } from '../../constants/layout' -import addUnitApi from '../../apis/addUnitApi' +import addUnitApi from '../../apis/unit/addUnitApi' import { MyButton } from '../../components/MyButton' export function UnitAddScreen() { @@ -18,7 +18,7 @@ export function UnitAddScreen() { const [Unitname, setUnitname] = useState('') const [Unitslogan, setUnitslogan] = useState('') - const [Logo, setLogo] = useState('')s + const [Logo, setLogo] = useState('') return ( diff --git a/front-end/app/src/screens/setting-screens/UnitMgtScreen.js b/front-end/app/src/screens/setting-screens/UnitMgtScreen.js index 1b444375..dfc33201 100644 --- a/front-end/app/src/screens/setting-screens/UnitMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/UnitMgtScreen.js @@ -3,8 +3,8 @@ import { SafeAreaView, View, StyleSheet, Alert } from 'react-native' import { TextInput } from 'react-native-paper' import { ImagePicker } from '../../components/ImagePicker' import { window } from '../../constants/layout' -import updateUnitApi from '../../apis/addUnitApi' -import updateUnitLogoApi from '../../apis/updateUnitLogoApi' +import updateUnitApi from '../../apis/unit/addUnitApi' +import updateUnitLogoApi from '../../apis/unit/updateUnitLogoApi' import { MyButton } from '../../components/MyButton' export function UnitMgtScreen() { diff --git a/front-end/app/src/screens/setting-screens/UserAddScreen.js b/front-end/app/src/screens/setting-screens/UserAddScreen.js index 853a9f70..b2c928b5 100644 --- a/front-end/app/src/screens/setting-screens/UserAddScreen.js +++ b/front-end/app/src/screens/setting-screens/UserAddScreen.js @@ -6,7 +6,7 @@ import { GuideText } from '../../components/GuideText' import { window } from '../../constants/layout' import DropDownPicker from 'react-native-dropdown-picker' import { MyButton } from '../../components/MyButton' -import addUserApi from '../../apis/addUserApi' +import addUserApi from '../../apis/user/addUserApi' const AccountTypeItems = [ { label: '지휘관', value: 'Commander' }, diff --git a/front-end/app/src/screens/setting-screens/UserMgtScreen.js b/front-end/app/src/screens/setting-screens/UserMgtScreen.js index 6e59c7ff..b59dc324 100644 --- a/front-end/app/src/screens/setting-screens/UserMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/UserMgtScreen.js @@ -3,7 +3,7 @@ import { FAB, Avatar, Colors } from 'react-native-paper' //prettier-ignore import { SafeAreaView, StyleSheet, TouchableOpacity, ScrollView, Text, View } from 'react-native' import { useNavigation } from '@react-navigation/native' -import searchUserApi from '../../apis/searchUserApi' +import searchUserApi from '../../apis/user/searchUserApi' import { useNunitoFonts } from '../../hooks/useNunitoFonts' const Item = ({ Name, Rank, pic, Position }) => ( diff --git a/front-end/app/src/screens/setting-screens/UserUpdateScreen.js b/front-end/app/src/screens/setting-screens/UserUpdateScreen.js index 621ce1e1..a97dda9b 100644 --- a/front-end/app/src/screens/setting-screens/UserUpdateScreen.js +++ b/front-end/app/src/screens/setting-screens/UserUpdateScreen.js @@ -6,8 +6,8 @@ import { GuideText } from '../../components/GuideText' import { window } from '../../constants/layout' import DropDownPicker from 'react-native-dropdown-picker' import { MyButton } from '../../components/MyButton' -import updateUserApi from '../../apis/updateUserApi' -import updateUserPicApi from '../../apis/updateUserPicApi' +import updateUserApi from '../../apis/user/updateUserApi' +import updateUserPicApi from '../../apis/user/updateUserPicApi' import { userState } from '../../states/userState' import { useRecoilState } from 'recoil' import { ImagePicker } from '../../components/ImagePicker' From b815680156228f4774a8b79199ebd952efdcfaab Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Wed, 19 Oct 2022 15:22:54 +0000 Subject: [PATCH 19/48] [Feat]: #100 Integrated user settings with backend --- back-end/controllers/unitControllers.js | 13 + back-end/controllers/userControllers.js | 69 ++++- back-end/models/userModel.js | 15 +- back-end/routes/unitRoutes.js | 5 +- back-end/routes/userRoutes.js | 2 + front-end/web-next/pages/home.js | 15 +- front-end/web-next/pages/settings.js | 360 +++++++++++++--------- front-end/web-next/pages/settings/unit.js | 2 - 8 files changed, 312 insertions(+), 169 deletions(-) diff --git a/back-end/controllers/unitControllers.js b/back-end/controllers/unitControllers.js index 24c171ac..e77af423 100644 --- a/back-end/controllers/unitControllers.js +++ b/back-end/controllers/unitControllers.js @@ -2,6 +2,18 @@ const asyncHandler = require("express-async-handler"); const User = require("../models/userModel"); const Unit = require("../models/unitModel"); +//@description GET new unit +//@route GET /api/unit/get +//@access Protected +const getUnit = asyncHandler(async (req, res) => { + const keyword = req.query.search + if (keyword) { + res.send(await Unit.find({ _id: { $eq: keyword }})); //.find({ _id: { $ne: req.user._id } })); + } else { + res.status(400); + throw new Error("잘못된 요청입니다."); + } +}) //@description Add new unit //@route POST /api/unit //@access Protected @@ -129,6 +141,7 @@ const updateLogo = asyncHandler(async (req, res) => { }); module.exports = { + getUnit, updateUnit, updateLogo, addUnit diff --git a/back-end/controllers/userControllers.js b/back-end/controllers/userControllers.js index e4dd1b60..6e8c6204 100644 --- a/back-end/controllers/userControllers.js +++ b/back-end/controllers/userControllers.js @@ -43,7 +43,8 @@ const allUsers = asyncHandler(async (req, res) => { if (index) { res.send(users.slice(parseInt(index) * 4, parseInt(index) * 4 + 4)); } else if (keyword) { - res.send(await User.find({ _id: { $eq: keyword }}, {password: 0})); //.find({ _id: { $ne: req.user._id } })); + let user = await User.find({ _id: { $eq: keyword }}, {password: 0}) + res.send(user); //.find({ _id: { $ne: req.user._id } })); } else { res.status(400); throw new Error("잘못된 요청입니다."); @@ -269,6 +270,71 @@ const updateUser = asyncHandler(async (req, res) => { } }); +//@description update user info +//@route PUT /api/user/updateweb +//@access protect +const updateUser2 = asyncHandler(async (req, res) => { + const { + DID, + Rank, + Role, + email, + milNumber, + number + } = req.body; + + if (!DID && !Rank && !Role) { + res.status(400); + throw new Error("수정할 정보를 입력하세요."); + } + + const DoDID = req.user.DoDID; + const userDb = await User.findOne({ + DoDID + }); + + if (!userDb) { + res.status(400); + throw new Error("등록되지 않은 사용자입니다."); + } + + if (!userDb.is_registered) { + res.status(400); + throw new Error("가입 후 시도하세요."); + } + + const noData = ""; + const updatedUser = await User.findByIdAndUpdate( + userDb._id, { + DoDID: DID != noData ? DID : userDb.DoDID, + Rank: Rank != noData ? Rank : userDb.Rank, + Role: Role != noData ? Role : userDb.Role, + email: email != noData ? email : userDb.email, + milNumber: milNumber != noData ? milNumber : userDb.milNumber, + number: number != noData ? number : userDb.number + }, { + new: true, + } + ) + + if (!updatedUser) { + res.status(400); + throw new Error("사용자를 찾을 수 없습니다."); + } else { + res.status(201).json({ + _id: updatedUser._id, + Name: updatedUser.Name, + Rank: updatedUser.Rank, + DoDID: updatedUser.DoDID, + email: updatedUser.email, + milNumber: updatedUser.milNumber, + number: updatedUser.number, + Role: updatedUser.Role, + pic: updatedUser.pic, + }); + } +}); + //@description update user picture //@route PUT /api/user/pic //@access protect @@ -329,5 +395,6 @@ module.exports = { registerUser, authUser, updateUser, + updateUser2, updatePic }; diff --git a/back-end/models/userModel.js b/back-end/models/userModel.js index cfdaae87..5385b158 100644 --- a/back-end/models/userModel.js +++ b/back-end/models/userModel.js @@ -20,6 +20,9 @@ const userSchema = mongoose.Schema({ type: String, required: true }, + Role: { + type: String, + }, Type: { type: String, required: true @@ -33,23 +36,19 @@ const userSchema = mongoose.Schema({ }, Position: { type: String, - required: false, - default: "no data" + required: false }, email: { type: String, - required: false, - default: "no data" + required: false }, milNumber: { type: String, - required: false, - default: "no data" + required: false }, number: { type: String, - required: false, - default: "no data" + required: false }, pic: { type: String, diff --git a/back-end/routes/unitRoutes.js b/back-end/routes/unitRoutes.js index 605027a9..766c7744 100644 --- a/back-end/routes/unitRoutes.js +++ b/back-end/routes/unitRoutes.js @@ -2,7 +2,8 @@ const express = require("express"); const { updateUnit, updateLogo, - addUnit + addUnit, + getUnit } = require("../controllers/unitControllers"); const { protect, @@ -14,5 +15,7 @@ const router = express.Router(); router.route("/").post(onlyAdmin, addUnit); router.route("/").put(onlyAdmin, updateUnit); router.route("/logo").put(onlyAdmin, updateLogo); +router.route("/get").get(onlyAdmin, getUnit); + module.exports = router; diff --git a/back-end/routes/userRoutes.js b/back-end/routes/userRoutes.js index fc49d5f9..5c9fe179 100644 --- a/back-end/routes/userRoutes.js +++ b/back-end/routes/userRoutes.js @@ -5,6 +5,7 @@ const { allUsers, addUser, updateUser, + updateUser2, updatePic } = require("../controllers/userControllers"); const { @@ -16,6 +17,7 @@ const router = express.Router(); router.route("/").get(protect, allUsers); //protect, router.route("/").put(protect, updateUser); +router.route("/updateweb").post(onlyAdmin, updateUser2); router.route("/pic").put(protect, updatePic); //protect, router.route("/add").post(onlyAdmin, addUser); router.route("/register").post(registerUser); diff --git a/front-end/web-next/pages/home.js b/front-end/web-next/pages/home.js index 61103513..f25a4def 100644 --- a/front-end/web-next/pages/home.js +++ b/front-end/web-next/pages/home.js @@ -109,14 +109,16 @@ const Home = (props) => {
} -const backendroot = process.env.NEXT_PUBLIC_BACKEND_ROOT -let endpoint = backendroot + 'api/user?search=' -const secret = process.env.JWT_SECRET + export async function getServerSideProps(context) { + const backendroot = process.env.NEXT_PUBLIC_BACKEND_ROOT + const endpoint = backendroot + 'api/user?search=' + const secret = process.env.JWT_SECRET const JWTtoken = context.req.cookies['usercookie']; // => 'value' const { payload } = await jwtVerify(JWTtoken, new TextEncoder().encode(secret)) let id = payload['id'] + console.log(endpoint + id) const options = { // The method is POST because we are sending data. method: 'GET', @@ -132,8 +134,9 @@ export async function getServerSideProps(context) { //Pass data to the page via props // console.log('hi') // console.log(data[0]['Unit']) - if (data[0]['Unit']) { - endpoint = backendroot + 'api/unit/get?search=' + + if (data[0] && data[0]['Unit']) { + let endpoint2 = backendroot + 'api/unit/get?search=' const options = { // The method is POST because we are sending data. method: 'GET', @@ -143,7 +146,7 @@ export async function getServerSideProps(context) { 'Authorization': 'Bearer ' + JWTtoken } } - const res2 = await fetch(endpoint + data[0]['Unit'], options) + const res2 = await fetch(endpoint2 + data[0]['Unit'], options) const data2 = await res2.json() return { props: { data, data2 } } diff --git a/front-end/web-next/pages/settings.js b/front-end/web-next/pages/settings.js index f3b88b1c..a99839e3 100644 --- a/front-end/web-next/pages/settings.js +++ b/front-end/web-next/pages/settings.js @@ -1,32 +1,35 @@ import Head from 'next/head' import { Button, Input, Upload, Image, TreeSelect, Form, PageHeader, Breadcrumb } from 'antd'; import styles from '../styles/usersettings.module.css' -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; +import { jwtVerify } from 'jose'; +import { getCookie } from 'cookies-next'; + +const backendroot = process.env.NEXT_PUBLIC_BACKEND_ROOT + const RankData = [ - { - title: '병사', - value: 'title1', - children: [{ title: '이병', value: 'PVT', }, { title: '일병', value: 'PFC', }, { title: '상병', value: 'CPL', }, { title: '병장', value: 'SGT', }] - }, - { - title: '부사관', - value: 'title2', - children: [{ title: '하사', value: 'SST', }, { title: '중사', value: 'SFC', }, { title: '상사', value: 'MST', }, { title: '원사', value: 'SGM', }] - }, - { - title: '장교', - value: 'title3', - children: [{ title: '소위', value: 'SECLIU', }, { title: '중위', value: 'LIU', }, { title: '대위', value: 'CPT', }, { title: '소령', value: 'MAJ', }, { title: '중령', value: 'LTC', }, { title: '대령', value: 'COL', }] - }, - { - title: '장군', - value: 'title4', - children: [{ title: '준장', value: 'BG', }, { title: '소장', value: 'MG', }, { title: '중장', value: 'LG', }, { title: '대장', value: 'GEN', }] - } + { + title: '병사', + value: 'title1', + children: [{ title: '이병', value: 'PVT', }, { title: '일병', value: 'PFC', }, { title: '상병', value: 'CPL', }, { title: '병장', value: 'SGT', }] + }, + { + title: '부사관', + value: 'title2', + children: [{ title: '하사', value: 'SST', }, { title: '중사', value: 'SFC', }, { title: '상사', value: 'MST', }, { title: '원사', value: 'SGM', }] + }, + { + title: '장교', + value: 'title3', + children: [{ title: '소위', value: 'SECLIU', }, { title: '중위', value: 'LIU', }, { title: '대위', value: 'CPT', }, { title: '소령', value: 'MAJ', }, { title: '중령', value: 'LTC', }, { title: '대령', value: 'COL', }] + }, + { + title: '장군', + value: 'title4', + children: [{ title: '준장', value: 'BG', }, { title: '소장', value: 'MG', }, { title: '중장', value: 'LG', }, { title: '대장', value: 'GEN', }] + } ]; -let submitnewuser = async (event) => { - console.log('hi') -} + let submituserimg = async (event) => { console.log('hi') @@ -35,17 +38,49 @@ let submituserimg = async (event) => { let submitnewpassword = async (event) => { console.log('pass') } - +const Settings = (props) => { + let userprops = props['data'][0] -const Settings = () => { - //TreeData1 - const [DoDID, setDoDID] = useState(); - const [Rank, setRank] = useState(); - const [Position, setPosition] = useState(); - const [Armymail, setArmymail] = useState(); - const [Armyphone, setArmyphone] = useState(); - const [Phone, setPhone] = useState(); + + + const [DoDID, setDoDID] = useState(userprops.DoDID); + const [Rank, setRank] = useState(userprops.Rank); + const [Position, setPosition] = useState(userprops.Role); + const [Armymail, setArmymail] = useState(userprops.email); + const [Armyphone, setArmyphone] = useState(userprops.milNumber); + const [Phone, setPhone] = useState(userprops.number); + let submitnewuser = async (event) => { + let endpoint = backendroot + 'api/user/updateweb' + const data = { + DID: DoDID, + Rank: Rank, + Role: Position, + email: Armymail, + milNumber: Armyphone, + number: Phone + } + const JSONdata = JSON.stringify(data) + const options = { + // The method is POST because we are sending data. + method: 'POST', + // Tell the server we're sending JSON. + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + getCookie('usercookie') + }, + // Body of the request is the JSON data we created above. + body: JSONdata, + } + const response = await fetch(endpoint, options) + const result = await response.json() + if (result['DoDID']) { + window.location.href = "/"; + } else { + seterror1(result['message']) + } + console.log(result) + } const [uploadedprofilelogo, setuploadedprofilelogo] = useState("none") @@ -68,137 +103,160 @@ const Settings = () => { } }; return <> - - 유저 설정 - -
- - 계정설정 - - 부대설정 - - - 보고체계 설정 - - - hi - - } style={{backgroundColor: "white", boxShadow: 'inset 0 -3em 3em rgba(0, 0, 0, 0.1), 0 0 0 2px rgb(255, 255, 255), 0.3em 0.3em 1em rgba(0, 0, 0, 0.3)'}}/> - -
-
-
-

군인정보 수정

-

군번

- - { setDoDID(event.target.value) }} /> - -

계급

- ({ - validator(_, value) { - if (value == 'title1' || value == 'title2' || value == 'title3' || value == 'title4') { - return Promise.reject('계급을 선택해 주세요') - } else { - return Promise.resolve() - } - } - })]}> - - -

직책

- - { setPosition(event.target.value) }} /> - -

군메일

- - { setArmymail(event.target.value) }} /> - -

(군)전화번호

- - { setArmyphone(event.target.value) }} /> - -

휴대폰번호

- - { setPhone(event.target.value) }} /> - - -
- -

{error1}fd

-

{success1}

- -
-
-
-
- -
-
-

프로필 사진 번경

-
-
- -
-
- setuploadedprofilelogo(image)}> - 사진을 드레그 해주세요 -

- -
- - -

error

-

+ + 유저 설정 + +
+ + 계정설정 + + 부대설정 + + + 보고체계 설정 + + + hi + + } style={{ backgroundColor: "white", boxShadow: 'inset 0 -3em 3em rgba(0, 0, 0, 0.1), 0 0 0 2px rgb(255, 255, 255), 0.3em 0.3em 1em rgba(0, 0, 0, 0.3)' }} /> +
+
+ +

군인정보 수정

+

군번

+ + { setDoDID(event.target.value) }} /> + +

계급

+ ({ + validator(_, value) { + if (value == 'title1' || value == 'title2' || value == 'title3' || value == 'title4') { + return Promise.reject('계급을 선택해 주세요') + } else { + return Promise.resolve() + } + } + })]}> + + +

직책

+ + { setPosition(event.target.value) }} /> + +

군메일

+ + { setArmymail(event.target.value) }} /> + +

(군)전화번호

+ + { setArmyphone(event.target.value) }} /> + +

휴대폰번호

+ + { setPhone(event.target.value) }} /> -
+ +
+ +

{error1}

+

{success1}

+
+
+
- -
+
+
+

프로필 사진 번경

+
+
+ +
+
+ setuploadedprofilelogo(image)}> + 사진을 드레그 해주세요 +

+ +
+ + +

error

+

+
+
-
-
- -

비밀번호 변경

-

현재 비밀번호

- - { setcurrpassword(event.target.value) }} /> - -

새 비밀번호

- - { setnewpassword1(event.target.value) }} /> - -

새 비밀번호 확인

- ({ +
+
+ +
+ + +
+
+
+

비밀번호 변경

+

현재 비밀번호

+ + { setcurrpassword(event.target.value) }} /> + +

새 비밀번호

+ + { setnewpassword1(event.target.value) }} /> + +

새 비밀번호 확인

+ ({ validator(_, value) { - if (!value || getFieldValue('새 비밀번호') === value) { - return Promise.resolve(); - } - return Promise.reject(new Error('비밀번호가 일치하지 않습니다!')); + if (!value || getFieldValue('새 비밀번호') === value) { + return Promise.resolve(); + } + return Promise.reject(new Error('비밀번호가 일치하지 않습니다!')); }, })]}> - { setnewpassword2(event.target.value) }} /> - - -
- -

{error3}fd

-

{success3}

- -
-
-
+ { setnewpassword2(event.target.value) }} /> + + +
+ +

{error3}fd

+

{success3}

+ +
+
+ +
-
- - + + } + +export async function getServerSideProps(context) { + let endpoint = backendroot + 'api/user?search=' + const secret = process.env.JWT_SECRET + const JWTtoken = context.req.cookies['usercookie']; // => 'value' + const { payload } = await jwtVerify(JWTtoken, new TextEncoder().encode(secret)) + let id = payload['id'] + const options = { + // The method is POST because we are sending data. + method: 'GET', + // Tell the server we're sending JSON. + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + JWTtoken + } + } + //Fetch data from external API + const res = await fetch(endpoint + id, options) + const data = await res.json() + + return { props: { data } } +} + export default Settings; \ No newline at end of file diff --git a/front-end/web-next/pages/settings/unit.js b/front-end/web-next/pages/settings/unit.js index e3fb4275..a52fe6a8 100644 --- a/front-end/web-next/pages/settings/unit.js +++ b/front-end/web-next/pages/settings/unit.js @@ -158,7 +158,6 @@ const UnitSettings = () => { } const response = await fetch(endpoint, options) const result = await response.json() - console.log(result) if (result['Invcode']) { seterror3("") setsuccess3("성공. 초대코드: " + result['Invcode']) @@ -166,7 +165,6 @@ const UnitSettings = () => { setsuccess3("") seterror3(result['message']) } - console.log(result) } From 26bda1b5c3637fc223a3a4a7cb98661f46df61b2 Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Thu, 20 Oct 2022 11:51:22 +0000 Subject: [PATCH 20/48] [Feat]: #108 middleware encryption function completed --- .../web-next/encryption/userencryption.js | 55 ++++++++++-- front-end/web-next/package-lock.json | 85 +++++++++++++++++-- front-end/web-next/package.json | 5 +- front-end/web-next/pages/home.js | 7 +- 4 files changed, 132 insertions(+), 20 deletions(-) diff --git a/front-end/web-next/encryption/userencryption.js b/front-end/web-next/encryption/userencryption.js index 4d0cf757..de7de927 100644 --- a/front-end/web-next/encryption/userencryption.js +++ b/front-end/web-next/encryption/userencryption.js @@ -1,18 +1,57 @@ const { SecretClient } = require("@azure/keyvault-secrets"); const { ClientSecretCredential } = require("@azure/identity"); +const { CryptoJS } = require("crypto-js") +var SHA256 = require("crypto-js/sha256"); +var enc = require("crypto-js/enc-hex"); +var enc2 = require('crypto-js/enc-utf8') +var AES = require("crypto-js/aes"); + +const { v4: uuidv4 } = require('uuid'); + const tenantId = process.env.AZURE_TENANT_ID const clientId = process.env.AZURE_CLIENT_ID const clientSecret = process.env.AZURE_CLIENT_SECRET +const credential = new ClientSecretCredential(tenantId, clientId, clientSecret); +const url = "https://" + 'vault-rokasrs' + ".vault.azure.net"; +const client = new SecretClient(url, credential); + +function hex_to_ascii(str1) + { + var hex = str1.toString(); + var str = ''; + for (var n = 0; n < hex.length; n += 2) { + str += String.fromCharCode(parseInt(hex.substr(n, 2), 16)); + } + return str; + } + +function generateKey(IV){ + return SHA256(IV); +} export async function encryptuser(id, plaintext) { - const credential = new ClientSecretCredential(tenantId, clientId, clientSecret); - const url = "https://" + 'vault-rokasrs' + ".vault.azure.net"; - const client = new SecretClient(url, credential); - console.log(client) - const secretName = 'secret1'; - const result = await client.setSecret(secretName, "MySecretValue"); - const secret = await client.getSecret(secretName); - console.log("secret: ", secret['value']); + + try { //secret exists + console.log(plaintext) + const secret = await client.getSecret(id); + console.log('secret exists') + + + let ciphertext = AES.encrypt(plaintext, secret.value).toString() + //return ciphertext + let bytes = AES.decrypt(ciphertext.toString(), secret.value) + return hex_to_ascii(bytes.toString(enc2.Utf8)) + + //console.log(originalText) + + } catch { //make new secret + let key = generateKey(uuidv4()) + let parsedkey = key.toString(enc.Hex) + const result = await client.setSecret(id, parsedkey); + //console.log(result) + + } + return 'hi' } diff --git a/front-end/web-next/package-lock.json b/front-end/web-next/package-lock.json index ab2f77f7..d10c1b97 100644 --- a/front-end/web-next/package-lock.json +++ b/front-end/web-next/package-lock.json @@ -17,6 +17,8 @@ "colors": "^1.4.0", "concurrently": "^7.4.0", "cookies-next": "^2.1.1", + "crypto-js": "^4.1.1", + "cryptojs": "^2.5.3", "formik-antd": "^2.0.4", "jose": "^4.10.0", "next": "^12.3.1", @@ -26,7 +28,8 @@ "react-icons": "^4.4.0", "react-infinite-scroll-component": "^6.1.0", "react-organizational-chart": "^2.2.0", - "util": "^0.12.4" + "util": "^0.12.4", + "uuid": "^9.0.0" }, "devDependencies": { "eslint": "8.24.0", @@ -190,6 +193,14 @@ "node": ">=12.0.0" } }, + "node_modules/@azure/core-rest-pipeline/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@azure/core-tracing": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.1.tgz", @@ -239,6 +250,14 @@ "node": ">=12.0.0" } }, + "node_modules/@azure/identity/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@azure/keyvault-secrets": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/@azure/keyvault-secrets/-/keyvault-secrets-4.6.0.tgz", @@ -303,6 +322,14 @@ "node": "10 || 12 || 14 || 16 || 18" } }, + "node_modules/@azure/msal-node/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -2037,6 +2064,19 @@ "node": ">= 8" } }, + "node_modules/crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, + "node_modules/cryptojs": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/cryptojs/-/cryptojs-2.5.3.tgz", + "integrity": "sha512-+rdPl1UCxE8s3R94NNn+zMKOiI4MJ7dyh3X0c5uBL3btDr4zQ6acd7f9mY7Wb5MrccZEi2Rrha3OEtLcc5XXog==", + "engines": { + "node": "*" + } + }, "node_modules/csstype": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", @@ -5664,9 +5704,9 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "bin": { "uuid": "dist/bin/uuid" } @@ -5939,6 +5979,13 @@ "https-proxy-agent": "^5.0.0", "tslib": "^2.2.0", "uuid": "^8.3.0" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } } }, "@azure/core-tracing": { @@ -5979,6 +6026,13 @@ "stoppable": "^1.1.0", "tslib": "^2.2.0", "uuid": "^8.3.0" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } } }, "@azure/keyvault-secrets": { @@ -6028,6 +6082,13 @@ "@azure/msal-common": "^7.6.0", "jsonwebtoken": "^8.5.1", "uuid": "^8.3.0" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } } }, "@babel/code-frame": { @@ -7198,6 +7259,16 @@ "which": "^2.0.1" } }, + "crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, + "cryptojs": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/cryptojs/-/cryptojs-2.5.3.tgz", + "integrity": "sha512-+rdPl1UCxE8s3R94NNn+zMKOiI4MJ7dyh3X0c5uBL3btDr4zQ6acd7f9mY7Wb5MrccZEi2Rrha3OEtLcc5XXog==" + }, "csstype": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", @@ -9686,9 +9757,9 @@ } }, "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" }, "which": { "version": "2.0.2", diff --git a/front-end/web-next/package.json b/front-end/web-next/package.json index 7a2dafa7..7f107908 100644 --- a/front-end/web-next/package.json +++ b/front-end/web-next/package.json @@ -20,6 +20,8 @@ "colors": "^1.4.0", "concurrently": "^7.4.0", "cookies-next": "^2.1.1", + "crypto-js": "^4.1.1", + "cryptojs": "^2.5.3", "formik-antd": "^2.0.4", "jose": "^4.10.0", "next": "^12.3.1", @@ -29,7 +31,8 @@ "react-icons": "^4.4.0", "react-infinite-scroll-component": "^6.1.0", "react-organizational-chart": "^2.2.0", - "util": "^0.12.4" + "util": "^0.12.4", + "uuid": "^9.0.0" }, "devDependencies": { "eslint": "8.24.0", diff --git a/front-end/web-next/pages/home.js b/front-end/web-next/pages/home.js index f25a4def..d9d5c96f 100644 --- a/front-end/web-next/pages/home.js +++ b/front-end/web-next/pages/home.js @@ -3,13 +3,13 @@ import style from '../styles/homepage.module.css' import Image from 'next/image' import unitlogo from '../img/unitlogo.png' import { Descriptions, Tabs, Avatar, List, PageHeader, Button, Input, Space } from 'antd'; +import {encryptuser} from '../encryption/userencryption' import { jwtVerify } from 'jose'; - +encryptuser('test1', 'hfipoawefjapoiwfhawpoeifjwf') const { Search } = Input; let onSearch = async (event) => { - console.log('hi') } const data = [ @@ -29,7 +29,6 @@ const data = [ const Home = (props) => { - console.log(props) let props1 = props['data'][0] let props2 = props['data2'][0] @@ -112,13 +111,13 @@ const Home = (props) => { export async function getServerSideProps(context) { + const backendroot = process.env.NEXT_PUBLIC_BACKEND_ROOT const endpoint = backendroot + 'api/user?search=' const secret = process.env.JWT_SECRET const JWTtoken = context.req.cookies['usercookie']; // => 'value' const { payload } = await jwtVerify(JWTtoken, new TextEncoder().encode(secret)) let id = payload['id'] - console.log(endpoint + id) const options = { // The method is POST because we are sending data. method: 'GET', From c0b4cbee3c05ff95328c583fffbf025b9e912c1a Mon Sep 17 00:00:00 2001 From: hyeongmin Kim <113012760+gudmin0526@users.noreply.github.com> Date: Thu, 20 Oct 2022 13:26:40 +0000 Subject: [PATCH 21/48] Feat: Add some func to report related component --- back-end/controllers/userControllers.js | 149 ++++++++++-------- .../src/apis/report-sys/addReportsysApi.js | 3 +- .../src/apis/report-sys/getReportsysApi.js | 1 - .../src/apis/report-sys/removeReportsysApi.js | 3 +- .../app/src/apis/report/addCommentApi.js | 10 +- front-end/app/src/apis/user/searchUserApi.js | 11 +- .../app/src/components/ChatListItem/index.js | 10 +- .../app/src/components/GuideText/index.js | 4 +- .../app/src/components/MyButton/index.js | 8 +- .../app/src/components/OrgListItem/index.js | 18 +-- front-end/app/src/components/Profile/index.js | 26 +-- .../app/src/components/ReportComment/index.js | 24 ++- .../app/src/components/ReportContent/index.js | 4 +- .../app/src/components/ReportGroup/index.js | 38 ++--- .../app/src/components/ReportGroup/style.js | 23 +-- .../app/src/components/ReportHeader/index.js | 12 +- .../src/components/ReportListItem/index.js | 1 - .../app/src/components/UserCard/index.js | 16 ++ .../app/src/components/UserCard/style.js | 21 +++ front-end/app/src/data/procData.js | 5 + front-end/app/src/data/ranks.js | 45 +++--- .../report-screens/CreateReportScreen.js | 18 ++- .../screens/setting-screens/SettingScreen.js | 36 ++++- .../screens/setting-screens/SysMgtScreen.js | 66 ++++++-- .../screens/setting-screens/UnitAddScreen.js | 2 +- .../screens/setting-screens/UnitMgtScreen.js | 1 + .../screens/setting-screens/UserMgtScreen.js | 9 +- 27 files changed, 337 insertions(+), 227 deletions(-) create mode 100644 front-end/app/src/components/UserCard/index.js create mode 100644 front-end/app/src/components/UserCard/style.js diff --git a/back-end/controllers/userControllers.js b/back-end/controllers/userControllers.js index e4dd1b60..5054d9be 100644 --- a/back-end/controllers/userControllers.js +++ b/back-end/controllers/userControllers.js @@ -8,14 +8,39 @@ const UnitM = require("../models/unitModel"); //@route GET /api/user?search=?index= //@access Protected const allUsers = asyncHandler(async (req, res) => { - const ranks = ["CV9", "CV8", "CV7", - "CV6", "CV5", "CV4", "CV3", "CV2", - "CV1", "PVT", "PFC", "CPL", "SGT", - "SST", "SFC", "MST", "SGM", "SEC", - "LIU", "LIU", "CPT", "MAJ", "LTC", - "COL", "BG", "MG", "LG", "GEN" + const ranks = [ + "CV9", + "CV8", + "CV7", + "CV6", + "CV5", + "CV4", + "CV3", + "CV2", + "CV1", + "PVT", + "PFC", + "CPL", + "SGT", + "SST", + "SFC", + "MST", + "SGM", + "SEC", + "LIU", + "LIU", + "CPT", + "MAJ", + "LTC", + "COL", + "BG", + "MG", + "LG", + "GEN", ]; - const keyword = req.query.search /*? + + console.log(req.query); + const keyword = req.query.search; /*? { $or: [{ Name: { @@ -33,35 +58,35 @@ const allUsers = asyncHandler(async (req, res) => { ], } : 0;*/ - users = await User.find({}, { - password: 0 - }); + users = await User.find( + {}, + { + password: 0, + } + ); users.sort(function (a, b) { - return (ranks.indexOf(b.Rank) + (b.is_registered ? 0 : 100)) - (ranks.indexOf(a.Rank) + (a.is_registered ? 0 : 100)); + return ( + ranks.indexOf(b.Rank) + + (b.is_registered ? 0 : 100) - + (ranks.indexOf(a.Rank) + (a.is_registered ? 0 : 100)) + ); }); const index = req.query.index; if (index) { res.send(users.slice(parseInt(index) * 4, parseInt(index) * 4 + 4)); } else if (keyword) { - res.send(await User.find({ _id: { $eq: keyword }}, {password: 0})); //.find({ _id: { $ne: req.user._id } })); + res.send(await User.find({ _id: { $eq: keyword } }, { password: 0 })); //.find({ _id: { $ne: req.user._id } })); } else { res.status(400); throw new Error("잘못된 요청입니다."); } - }); //@description Add new user //@route POST /api/user/add //@access Protected const addUser = asyncHandler(async (req, res) => { - const { - Rank, - Name, - DoDID, - Type - } = req.body; - + const { Rank, Name, DoDID, Type } = req.body; if (!Rank || !Name || !DoDID || !Type) { res.status(400); @@ -69,7 +94,7 @@ const addUser = asyncHandler(async (req, res) => { } const userExists = await User.findOne({ - DoDID + DoDID, }); if (userExists) { @@ -85,18 +110,20 @@ const addUser = asyncHandler(async (req, res) => { Rank, Type, Invcode, - Unit + Unit, }); const added = await UnitM.findByIdAndUpdate( - Unit._id, { + Unit._id, + { $push: { - Members: user._id + Members: user._id, }, - }, { + }, + { new: true, } - ) + ); if (user) { res.status(201).json({ @@ -106,7 +133,7 @@ const addUser = asyncHandler(async (req, res) => { DoDID: user.DoDID, Type: user.Type, Invcode: user.Invcode, - Unit: user.Unit + Unit: user.Unit, }); } else { res.status(400); @@ -118,12 +145,7 @@ const addUser = asyncHandler(async (req, res) => { //@route POST /api/user/register //@access Public const registerUser = asyncHandler(async (req, res) => { - const { - DoDID, - password, - pic, - Invcode - } = req.body; + const { DoDID, password, pic, Invcode } = req.body; //049opo6a if (!password || !DoDID || !Invcode) { res.status(400); @@ -131,7 +153,7 @@ const registerUser = asyncHandler(async (req, res) => { } const userDb = await User.findOne({ - DoDID + DoDID, }); if (!userDb) { @@ -150,14 +172,16 @@ const registerUser = asyncHandler(async (req, res) => { } const updatedUser = await User.findByIdAndUpdate( - userDb._id, { + userDb._id, + { password: await bcrypt.hash(password, await bcrypt.genSalt(10)), pic: pic, - is_registered: true - }, { + is_registered: true, + }, + { new: true, } - ) + ); if (!updatedUser) { res.status(400); @@ -177,16 +201,15 @@ const registerUser = asyncHandler(async (req, res) => { //@route POST /api/users/login //@access public const authUser = asyncHandler(async (req, res) => { - const { - DoDID, - password - } = req.body; + const { DoDID, password } = req.body; const user = await User.findOne({ - DoDID + DoDID, }); if (user && !user.is_registered) { res.status(400); - throw new Error("승인된 사용자이나 아직 등록되지 않았습니다. 계정 등록 후 이용해주세요."); + throw new Error( + "승인된 사용자이나 아직 등록되지 않았습니다. 계정 등록 후 이용해주세요." + ); } if (user && (await user.matchPassword(password))) { @@ -210,13 +233,7 @@ const authUser = asyncHandler(async (req, res) => { //@route PUT /api/user //@access protect const updateUser = asyncHandler(async (req, res) => { - const { - Rank, - Name, - email, - milNumber, - number - } = req.body; + const { Rank, Name, email, milNumber, number } = req.body; if (!Rank && !Name && !email && !milNumber && !number) { res.status(400); @@ -225,7 +242,7 @@ const updateUser = asyncHandler(async (req, res) => { const DoDID = req.user.DoDID; const userDb = await User.findOne({ - DoDID + DoDID, }); if (!userDb) { @@ -240,16 +257,18 @@ const updateUser = asyncHandler(async (req, res) => { const noData = ""; const updatedUser = await User.findByIdAndUpdate( - userDb._id, { + userDb._id, + { Rank: Rank != noData ? Rank : userDb.Rank, Name: Name != noData ? Name : userDb.Name, email: email != noData ? email : userDb.email, milNumber: milNumber != noData ? milNumber : userDb.milNumber, - number: number != noData ? number : userDb.number - }, { + number: number != noData ? number : userDb.number, + }, + { new: true, } - ) + ); if (!updatedUser) { res.status(400); @@ -273,9 +292,7 @@ const updateUser = asyncHandler(async (req, res) => { //@route PUT /api/user/pic //@access protect const updatePic = asyncHandler(async (req, res) => { - const { - pic - } = req.body; + const { pic } = req.body; if (!pic) { res.status(400); @@ -284,7 +301,7 @@ const updatePic = asyncHandler(async (req, res) => { const DoDID = req.user.DoDID; const userDb = await User.findOne({ - DoDID + DoDID, }); if (!userDb) { @@ -298,12 +315,14 @@ const updatePic = asyncHandler(async (req, res) => { } const updatedUser = await User.findByIdAndUpdate( - userDb._id, { - pic: pic - }, { + userDb._id, + { + pic: pic, + }, + { new: true, } - ) + ); if (!updatedUser) { res.status(400); @@ -329,5 +348,5 @@ module.exports = { registerUser, authUser, updateUser, - updatePic + updatePic, }; diff --git a/front-end/app/src/apis/report-sys/addReportsysApi.js b/front-end/app/src/apis/report-sys/addReportsysApi.js index 7267a4ec..7468a431 100644 --- a/front-end/app/src/apis/report-sys/addReportsysApi.js +++ b/front-end/app/src/apis/report-sys/addReportsysApi.js @@ -1,7 +1,7 @@ import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' -const addReportsysApi = async ({ Title, List }) => { +const addReportsysApi = async ({ Title, List, Unit }) => { try { const res = await fetch(URL + '/api/reportsys', { method: 'POST', @@ -11,6 +11,7 @@ const addReportsysApi = async ({ Title, List }) => { Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, }, body: JSON.stringify({ Title, List }), + user: JSON.stringify({ Unit }), }) return res.json() } catch (error) { diff --git a/front-end/app/src/apis/report-sys/getReportsysApi.js b/front-end/app/src/apis/report-sys/getReportsysApi.js index 6cf6454b..9ac831c0 100644 --- a/front-end/app/src/apis/report-sys/getReportsysApi.js +++ b/front-end/app/src/apis/report-sys/getReportsysApi.js @@ -3,7 +3,6 @@ import asyncStorage from '@react-native-async-storage/async-storage' const getReportsysApi = async (query) => { const searchQuery = query ? query : '' - console.log(URL + '/api/reportsys?search=' + searchQuery) try { const res = await fetch(URL + '/api/reportsys?search=' + searchQuery, { method: 'GET', diff --git a/front-end/app/src/apis/report-sys/removeReportsysApi.js b/front-end/app/src/apis/report-sys/removeReportsysApi.js index 1d72dbd0..5bb64b77 100644 --- a/front-end/app/src/apis/report-sys/removeReportsysApi.js +++ b/front-end/app/src/apis/report-sys/removeReportsysApi.js @@ -1,7 +1,7 @@ import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' -const removeReportsysApi = async ({ _id }) => { +const removeReportsysApi = async ({ _id, Unit }) => { try { const res = await fetch(URL + '/api/reportsys', { method: 'DELETE', @@ -11,6 +11,7 @@ const removeReportsysApi = async ({ _id }) => { Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, }, body: JSON.stringify({ _id }), + user: JSON.stringify({ Unit }), }) return res.json() } catch (error) { diff --git a/front-end/app/src/apis/report/addCommentApi.js b/front-end/app/src/apis/report/addCommentApi.js index a3ada46d..9ab9306a 100644 --- a/front-end/app/src/apis/report/addCommentApi.js +++ b/front-end/app/src/apis/report/addCommentApi.js @@ -10,14 +10,8 @@ const addCommentApi = async ({ Type, Content, Title, _id }) => { Accept: 'application/json', Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, }, - body: JSON.stringify({ - Type: Type, - Content: Content, - Title: Title, - }), - user: JSON.stringify({ - _id: _id, - }), + body: JSON.stringify({ Type, Content, Title }), + user: JSON.stringify({ _id }), }) return res.json() } catch (error) { diff --git a/front-end/app/src/apis/user/searchUserApi.js b/front-end/app/src/apis/user/searchUserApi.js index f4ca84af..4e9f090e 100644 --- a/front-end/app/src/apis/user/searchUserApi.js +++ b/front-end/app/src/apis/user/searchUserApi.js @@ -1,10 +1,13 @@ import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' -const searchUserApi = async (query) => { - const searchQuery = query ? query : '' +const searchUserApi = async ({ query, index }) => { + const reqUrl = query + ? URL + `/api/user?search=${query}` + : URL + `/api/user?index=${index}` + console.log(reqUrl) try { - const res = await fetch(URL + '/api/user?search=' + searchQuery, { + const res = await fetch(reqUrl, { method: 'GET', headers: { Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, @@ -12,7 +15,7 @@ const searchUserApi = async (query) => { }) return res.json() } catch (error) { - console.log(error) + // console.log(error) } } diff --git a/front-end/app/src/components/ChatListItem/index.js b/front-end/app/src/components/ChatListItem/index.js index 6c8fe703..5dd45e63 100644 --- a/front-end/app/src/components/ChatListItem/index.js +++ b/front-end/app/src/components/ChatListItem/index.js @@ -11,7 +11,7 @@ const chatHandler = () => { .catch((error) => console.log(error)) } -export const ChatListItem = ({ name, lastMessage, createAt }) => { +export const ChatListItem = (props) => { let [fontsLoaded] = useNunitoFonts() const navigation = useNavigation() @@ -28,13 +28,15 @@ export const ChatListItem = ({ name, lastMessage, createAt }) => { style={styles.avatar} /> - {name} + {props.name} - {lastMessage} + {props.lastMessage} - {moment('2022-10-03 04:00').fromNow()} + + {props.createdAt || moment('2022-10-03 04:00').fromNow()} + ) diff --git a/front-end/app/src/components/GuideText/index.js b/front-end/app/src/components/GuideText/index.js index 7e10264a..6245ac2f 100644 --- a/front-end/app/src/components/GuideText/index.js +++ b/front-end/app/src/components/GuideText/index.js @@ -2,8 +2,8 @@ import { Text } from 'react-native' import { useNunitoFonts } from '../../hooks/useNunitoFonts' import { styles } from './style' -export function GuideText({ guideText }) { +export function GuideText(props) { let [fontsLoaded] = useNunitoFonts() - return {guideText} + return {props.guideText} } diff --git a/front-end/app/src/components/MyButton/index.js b/front-end/app/src/components/MyButton/index.js index d706fe87..aba4fed4 100644 --- a/front-end/app/src/components/MyButton/index.js +++ b/front-end/app/src/components/MyButton/index.js @@ -4,14 +4,14 @@ import { useNavigation } from '@react-navigation/native' import { useNunitoFonts } from '../../hooks/useNunitoFonts' import { styles } from './style' -export function MyButton({ text, onPress }) { +export function MyButton(props) { let [fontsLoaded] = useNunitoFonts() const navigation = useNavigation() return ( - - - {text} + + + {props.text} ) diff --git a/front-end/app/src/components/OrgListItem/index.js b/front-end/app/src/components/OrgListItem/index.js index e19f6d5c..3ed0de38 100644 --- a/front-end/app/src/components/OrgListItem/index.js +++ b/front-end/app/src/components/OrgListItem/index.js @@ -20,6 +20,10 @@ const tempData = [ title: '중사 구창우', description: '통신부소대장', }, + { + title: '병장 김형민', + description: '분대장', + }, ] export function OrgListItem(props) { @@ -39,7 +43,7 @@ export function OrgListItem(props) { left={LeftImage} titleStyle={styles.titleStyle} descriptionStyle={styles.descriptionStyle} - key={idx} + key={idx.toString()} onPress={() => props.showModal({ name: item.title, @@ -50,18 +54,6 @@ export function OrgListItem(props) { } /> ))} - ( - - )} - > - - diff --git a/front-end/app/src/components/Profile/index.js b/front-end/app/src/components/Profile/index.js index f5e1eba0..82acaf98 100644 --- a/front-end/app/src/components/Profile/index.js +++ b/front-end/app/src/components/Profile/index.js @@ -3,30 +3,30 @@ import { Avatar } from 'react-native-paper' import { useNunitoFonts } from '../../hooks/useNunitoFonts' import { styles } from './style' -export function Profile( - { - name = '병장 김형민', - position = '본부중대 통신', - size = 45, - src = require('../../assets/images/avatar.png'), - }, - props -) { +export function Profile({ + name = '병장 김형민', + position = '본부중대 통신', + size = 45, + src = require('../../assets/images/avatar.png'), + style, + date, + right, +}) { let [fontsLoaded] = useNunitoFonts() return ( - + {name} {position} - {props.date && ( + {date && ( - {props.date} + {date} )} - {props.right} + {right} ) } diff --git a/front-end/app/src/components/ReportComment/index.js b/front-end/app/src/components/ReportComment/index.js index 15b98c97..4f53d441 100644 --- a/front-end/app/src/components/ReportComment/index.js +++ b/front-end/app/src/components/ReportComment/index.js @@ -5,25 +5,33 @@ import moment from 'moment' import { styles } from './style' import { Profile } from '../Profile' -export function ReportComment({ Name, position, Content, Type }) { +export function ReportComment(props) { let [fontsLoaded] = useNunitoFonts() - const type = - Type === 'emergency' ? '[긴급]' : Type === 'order' ? '[지시]' : '[보고]' + const Type = + props.Type === 'emergency' + ? '[긴급]' + : props.Type === 'order' + ? '[지시]' + : '[보고]' const color = - Type === 'emergency' ? 'red' : Type === 'order' ? Colors.amber700 : 'green' + props.Type === 'emergency' + ? 'red' + : props.Type === 'order' + ? Colors.amber700 + : 'green' return ( - {type} - {Content} + {Type} + {props.Content} ) diff --git a/front-end/app/src/components/ReportContent/index.js b/front-end/app/src/components/ReportContent/index.js index b8b30eb8..d1bed2e3 100644 --- a/front-end/app/src/components/ReportContent/index.js +++ b/front-end/app/src/components/ReportContent/index.js @@ -4,7 +4,7 @@ import { useNunitoFonts } from '../../hooks/useNunitoFonts' import { Profile } from '../Profile' import { styles } from './style' -export function ReportContent({ Content, Type }) { +export function ReportContent(props) { let [fontsLoaded] = useNunitoFonts() return ( @@ -16,7 +16,7 @@ export function ReportContent({ Content, Type }) { src={require('../../assets/images/avatar.png')} /> - {Content} + {props.Content} diff --git a/front-end/app/src/components/ReportGroup/index.js b/front-end/app/src/components/ReportGroup/index.js index 36b3c850..af701120 100644 --- a/front-end/app/src/components/ReportGroup/index.js +++ b/front-end/app/src/components/ReportGroup/index.js @@ -1,45 +1,27 @@ import React from 'react' -import { FlatList, Text, View, TouchableOpacity, Image } from 'react-native' -import { Avatar } from 'react-native-paper' +import { FlatList, Text, Image } from 'react-native' import { styles } from './style' import { useNunitoFonts } from '../../hooks/useNunitoFonts' - -// 배경 회색으로, 각 카드 elevation주기 +import { UserCard } from '../UserCard' const ItemSeparator = () => ( - - - + ) const renderItem = ({ item }) => ( - <> - - - {item.name} - {item.position} - - + ) -export function ReportGroup({ group, name, pic, isSetting = false }) { +export function ReportGroup(props) { let [fontsLoaded] = useNunitoFonts() return ( <> - {name === 'onDuty' ? '당직계통 보고체계' : '본부중대 보고체계'} + {props.name === 'onDuty' ? '당직계통 보고체계' : '본부중대 보고체계'} ) diff --git a/front-end/app/src/components/ReportGroup/style.js b/front-end/app/src/components/ReportGroup/style.js index 18d22734..142f7412 100644 --- a/front-end/app/src/components/ReportGroup/style.js +++ b/front-end/app/src/components/ReportGroup/style.js @@ -5,27 +5,12 @@ export const styles = StyleSheet.create({ container: { justifyContent: 'center', }, - view: { - borderRadius: 6, - alignItems: 'center', - paddingVertical: 3, - width: 75, - marginBottom: 2, - backgroundColor: Colors.grey200, - elevation: 3, - }, - image: { - marginBottom: 5, - }, - itemText: { - fontFamily: 'NunitoSans_400Regular', - fontSize: 12, - }, + image: { width: 30, height: 20, marginHorizontal: 7, marginTop: 38 }, text: { fontFamily: 'NunitoSans_300Light', - color: Colors.grey700, - fontSize: 13, - paddingTop: 1, + color: Colors.grey800, + fontSize: 12, + paddingTop: 3, marginBottom: 10, }, }) diff --git a/front-end/app/src/components/ReportHeader/index.js b/front-end/app/src/components/ReportHeader/index.js index ea56b823..90f7d633 100644 --- a/front-end/app/src/components/ReportHeader/index.js +++ b/front-end/app/src/components/ReportHeader/index.js @@ -3,25 +3,25 @@ import { Text, Colors } from 'react-native-paper' import { styles } from './style' import { useNunitoFonts } from '../../hooks/useNunitoFonts' -export function ReportHeader({ Title, isEnd, severity, date }) { +export function ReportHeader(props) { let [fontsLoaded] = useNunitoFonts() return ( - {Title} + {props.Title} - {isEnd ? '[종결]' : '[미종결]'} + {props.isEnd ? '[종결]' : '[미종결]'} 중요도: - {severity} - {date} + {props.severity} + {props.date} ) diff --git a/front-end/app/src/components/ReportListItem/index.js b/front-end/app/src/components/ReportListItem/index.js index ca994fb5..7011c750 100644 --- a/front-end/app/src/components/ReportListItem/index.js +++ b/front-end/app/src/components/ReportListItem/index.js @@ -7,7 +7,6 @@ import { styles } from './style' export function ReportListItem(props) { const { Title, isEnd, Content, severity, date, Type } = props - console.log(props) let [fontsLoaded] = useNunitoFonts() diff --git a/front-end/app/src/components/UserCard/index.js b/front-end/app/src/components/UserCard/index.js new file mode 100644 index 00000000..4b698088 --- /dev/null +++ b/front-end/app/src/components/UserCard/index.js @@ -0,0 +1,16 @@ +import { useNunitoFonts } from '../../hooks/useNunitoFonts' +import { View, Text } from 'react-native' +import { Avatar } from 'react-native-paper' +import { styles } from './style' + +export function UserCard(props) { + let [fontsLoaded] = useNunitoFonts() + + return ( + + + {props.name} + {props.position} + + ) +} diff --git a/front-end/app/src/components/UserCard/style.js b/front-end/app/src/components/UserCard/style.js new file mode 100644 index 00000000..a5889683 --- /dev/null +++ b/front-end/app/src/components/UserCard/style.js @@ -0,0 +1,21 @@ +import { StyleSheet } from 'react-native' +import { Colors } from 'react-native-paper' + +export const styles = StyleSheet.create({ + view: { + borderRadius: 6, + alignItems: 'center', + paddingVertical: 3, + width: 75, + marginBottom: 2, + backgroundColor: Colors.grey200, + elevation: 3, + }, + image: { + marginBottom: 5, + }, + text: { + fontFamily: 'NunitoSans_400Regular', + fontSize: 12, + }, +}) diff --git a/front-end/app/src/data/procData.js b/front-end/app/src/data/procData.js index 9db80c69..ebfbd3b7 100644 --- a/front-end/app/src/data/procData.js +++ b/front-end/app/src/data/procData.js @@ -3,24 +3,29 @@ const DATA = { { name: '중사 김택수', position: '당직사관', + source: require('../assets/images/avatar.png'), }, { name: '대위 정종찬', position: '당직사령', + source: require('../assets/images/avatar.png'), }, ], headquarter: [ { name: '중사 김택수', position: '통신부소대장', + source: require('../assets/images/avatar.png'), }, { name: '중위 정혁수', position: '통신소대장', + source: require('../assets/images/avatar.png'), }, { name: '대위 정종찬', position: '본부중대장', + source: require('../assets/images/avatar.png'), }, ], } diff --git a/front-end/app/src/data/ranks.js b/front-end/app/src/data/ranks.js index 0806fefc..1564496c 100644 --- a/front-end/app/src/data/ranks.js +++ b/front-end/app/src/data/ranks.js @@ -1,22 +1,31 @@ const RankItems = [ - { label: '대장', value: '대장' }, - { label: '준장', value: '준장' }, - { label: '소장', value: '소장' }, - { label: '대령', value: '대령' }, - { label: '중령', value: '중령' }, - { label: '소령', value: '소령' }, - { label: '대위', value: '대위' }, - { label: '중위', value: '중위' }, - { label: '소위', value: '소위' }, - { label: '준위', value: '준위' }, - { label: '원사', value: '원사' }, - { label: '상사', value: '상사' }, - { label: '중사', value: '중사' }, - { label: '하사', value: '하사' }, - { label: '병장', value: '병장' }, - { label: '상병', value: '상병' }, - { label: '일병', value: '일병' }, - { label: '이병', value: '이병' }, + { label: '대장', value: 'GEN' }, + { label: '준장', value: 'LG' }, + { label: '소장', value: 'MG' }, + { label: '준장', value: 'BG' }, + { label: '대령', value: 'COL' }, + { label: '중령', value: 'LTC' }, + { label: '소령', value: 'MAJ' }, + { label: '대위', value: 'CPT' }, + { label: '중위', value: 'LIU' }, + { label: '소위', value: 'SECLIU' }, + { label: '원사', value: 'SGM' }, + { label: '상사', value: 'MST' }, + { label: '중사', value: 'SFC' }, + { label: '하사', value: 'SST' }, + { label: '병장', value: 'SGT' }, + { label: '상병', value: 'CPL' }, + { label: '일병', value: 'PFC' }, + { label: '이병', value: 'PVT' }, + { label: '1급', value: 'CV1' }, + { label: '2급', value: 'CV2' }, + { label: '3급', value: 'CV3' }, + { label: '4급', value: 'CV4' }, + { label: '5급', value: 'CV5' }, + { label: '6급', value: 'CV6' }, + { label: '7급', value: 'CV7' }, + { label: '8급', value: 'CV8' }, + { label: '9급', value: 'CV9' }, ] export default RankItems diff --git a/front-end/app/src/screens/report-screens/CreateReportScreen.js b/front-end/app/src/screens/report-screens/CreateReportScreen.js index a6b1a9f3..c19937f0 100644 --- a/front-end/app/src/screens/report-screens/CreateReportScreen.js +++ b/front-end/app/src/screens/report-screens/CreateReportScreen.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React, { useState, useRef } from 'react' // prettier-ignore import { SafeAreaView, View, StyleSheet, ScrollView } from 'react-native' import { Colors, TextInput, IconButton } from 'react-native-paper' @@ -21,12 +21,15 @@ export function CreateReportScreen() { const [addedUser, setAddedUser] = useState([]) const onRemove = (_id) => { + console.log(addedUser) + setAddedUser(addedUser.filter((user) => user._id !== _id)) } const fetchUserHandler = async (query) => { const res = await searchUserApi(query) - console.log(res) + // console.log(res) + // console.log(addedUser) setAddedUser([...addedUser, res]) } @@ -48,7 +51,7 @@ export function CreateReportScreen() { const [title, setTitle] = useState('') const [text, setText] = useState('') - console.log(addedUser) + const plusRef = useRef(null) return ( @@ -113,13 +116,18 @@ export function CreateReportScreen() { dense={true} style={[styles.textInput, { marginBottom: 15 }]} onChangeText={(query) => setQuery(query)} + ref={plusRef} right={ fetchUserHandler(query)} + onPress={() => { + fetchUserHandler(query) + plusRef.current.blur() + }} + forceTextInputFocus={false} /> } onSubmitEditing={() => fetchUserHandler(query)} @@ -201,13 +209,13 @@ const styles = StyleSheet.create({ marginRight: 10, backgroundColor: Colors.grey200, paddingLeft: 5, + paddingVertical: 5, borderRadius: 8, elevation: 3, flexDirection: 'row', alignItems: 'center', }, icon: { - marginLeft: 5, backgroundColor: Colors.grey200, }, }) diff --git a/front-end/app/src/screens/setting-screens/SettingScreen.js b/front-end/app/src/screens/setting-screens/SettingScreen.js index 0c1664a0..80d38cea 100644 --- a/front-end/app/src/screens/setting-screens/SettingScreen.js +++ b/front-end/app/src/screens/setting-screens/SettingScreen.js @@ -39,14 +39,22 @@ export function SettingScreen() { left={() => } style={styles.listItem} onPress={() => - logoutHandler(() => navigation.navigate('LoginScreen')) + logoutHandler(() => + navigation.navigate('SettingNavigator', { + screen: 'LoginScreen', + }) + ) } /> } style={styles.listItem} - onPress={() => navigation.navigate('UserUpdateScreen')} + onPress={() => + navigation.navigate('SettingNavigator', { + screen: 'UserUpdateScreen', + }) + } /> } style={styles.listItem} - onPress={() => navigation.navigate('UserMgtScreen')} + onPress={() => + navigation.navigate('SettingNavigator', { + screen: 'UserMgtScreen', + }) + } /> } style={styles.listItem} - onPress={() => navigation.navigate('UnitMgtScreen')} + onPress={() => + navigation.navigate('SettingNavigator', { + screen: 'UnitMgtScreen', + }) + } /> } style={styles.listItem} - onPress={() => navigation.navigate('UnitAddScreen')} + onPress={() => + navigation.navigate('SettingNavigator', { + screen: 'UnitAddScreen', + }) + } /> } style={styles.listItem} - onPress={() => navigation.navigate('ProcMgtScreen')} + onPress={() => + navigation.navigate('SettingNavigator', { + screen: 'ProcMgtScreen', + }) + } /> diff --git a/front-end/app/src/screens/setting-screens/SysMgtScreen.js b/front-end/app/src/screens/setting-screens/SysMgtScreen.js index 94dbfff0..5c4ab98d 100644 --- a/front-end/app/src/screens/setting-screens/SysMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/SysMgtScreen.js @@ -1,8 +1,12 @@ -import React, { useState } from 'react' -import { SafeAreaView, ScrollView } from 'react-native' -import { Color, FAB } from 'react-native-paper' +import React, { useEffect, useState } from 'react' +import { SafeAreaView, ScrollView, StyleSheet } from 'react-native' +import { Colors, FAB, Provider, Modal } from 'react-native-paper' import { ReportGroup } from '../../components/ReportGroup' import DATA from '../../data/procData' +import { UserCard } from '../../components/UserCard' +import getReportsysApi from '../../apis/report-sys/getReportsysApi' +import addReportsysApi from '../../apis/report-sys/addReportsysApi' +import removeReportsysApi from '../../apis/report-sys/removeReportsysApi' // fetch로 데이터를 받아와서 넘겨줌. // 스크롤뷰로 나타냄. @@ -13,15 +17,57 @@ import DATA from '../../data/procData' // 1. Modal이 나을듯 // delete의 경우 button을 통해? - +const ItemSeparator = () => ( + +) export function SysMgtScreen() { + const [reportsys, setReportsys] = useState([]) + + useEffect(() => { + const getAllReportsysHandler = async () => { + const res = await getReportsysApi() + setReportsys(res) + } + getAllReportsysHandler() + }) + return ( - - - - - - + + + + + + + {/* {reportsys.map((sys) => )} */} + + + + navigation.navigate('UserAddScreen')} + color="white" + /> + + ) } + +const styles = StyleSheet.create({ + fab: { + borderRadius: 60, + height: 56, + width: 56, + position: 'absolute', + bottom: 25, + right: 20, + }, +}) diff --git a/front-end/app/src/screens/setting-screens/UnitAddScreen.js b/front-end/app/src/screens/setting-screens/UnitAddScreen.js index 3a31fb65..10829878 100644 --- a/front-end/app/src/screens/setting-screens/UnitAddScreen.js +++ b/front-end/app/src/screens/setting-screens/UnitAddScreen.js @@ -40,7 +40,7 @@ export function UnitAddScreen() { addUnitHandler({ Unitname, Unitslogan, Logo })} /> diff --git a/front-end/app/src/screens/setting-screens/UnitMgtScreen.js b/front-end/app/src/screens/setting-screens/UnitMgtScreen.js index dfc33201..55d4eb8a 100644 --- a/front-end/app/src/screens/setting-screens/UnitMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/UnitMgtScreen.js @@ -51,6 +51,7 @@ export function UnitMgtScreen() { updateUnitHandler({ Unitname, Unitslogan })} + style={{ marginBottom: 30 }} /> { const fetchUserHandler = async () => { - setData([...(await searchUserApi())]) + setData([...(await searchUserApi({ index: 1 }))]) } fetchUserHandler() }, []) @@ -45,12 +45,7 @@ export function UserMgtScreen() { /> ))} - navigation.navigate('UserAddScreen')} - color="white" - /> + ) } From 0e323d3ce5f5aa30f0ff7cf78adc7d663d099bb5 Mon Sep 17 00:00:00 2001 From: Yunseong Choe <68419358+marunemo@users.noreply.github.com> Date: Fri, 21 Oct 2022 04:42:52 +0000 Subject: [PATCH 22/48] [Feat]Fetch invited person data from userlist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 유저 정보들로 추가 인원 리스트를 채우도록 설정 --- front-end/web-next/componenets/MemoForm.js | 77 ++++++++++------------ 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/front-end/web-next/componenets/MemoForm.js b/front-end/web-next/componenets/MemoForm.js index ed7a0ae4..cf036e0f 100644 --- a/front-end/web-next/componenets/MemoForm.js +++ b/front-end/web-next/componenets/MemoForm.js @@ -1,9 +1,9 @@ import { useState, useCallback } from 'react'; import { Modal, Select, Button, Avatar, Row, Col } from 'antd'; import { PlusOutlined, ArrowRightOutlined, CloseOutlined } from '@ant-design/icons' +import { getCookie } from 'cookies-next'; import styles from '../styles/MemoForm.module.css'; - const orgType = [ { key: 0, @@ -54,43 +54,18 @@ const orgType = [ } ] - -const additionUser = [ - { - key: 0, - avatar: "https://joeschmoe.io/api/v1/random", - name: 'OOO', - rank: '소위', - position: '3중대 1소대장', - }, - { - key: 1, - avatar: "https://joeschmoe.io/api/v1/random", - name: 'XXX', - rank: '상사', - position: '3중대 행정보급관', - }, - { - key: 2, - avatar: "https://joeschmoe.io/api/v1/random", - name: 'XOX', - rank: '대위', - position: '3중대장', - } -] - function linkedUnit(unitList, key, onRemove = null) { if (unitList.length === 0) return; const unitLink = unitList.reduce((preLink, user, index) => { preLink.push( - + ); @@ -127,7 +102,7 @@ function linkedUnit(unitList, key, onRemove = null) { ) } -function additionalPerson(person, key, onRemove = null) { +function additionalPerson(user, key, onRemove = null) { return ( @@ -176,17 +151,31 @@ function MemoForm(props) { const [addUser, setAddUser] = useState([]); const [addUserList, setAddUserList] = useState([]); const [memoContent, setMemoContent] = useState(''); + const [fetchedInvitedList, setFetchedInvitedList] = useState([]); + + const fetchInvited = useCallback(async() => { + await fetch(process.env.NEXT_PUBLIC_BACKEND_ROOT + 'api/user?index=0', { + 'method': 'GET', + 'headers': { + 'content-type': 'application/json', + 'authorization': `Bearer ${getCookie('usercookie')}` + } + }) + .then(response => response.json()) + .then(data => setFetchedInvitedList(data)) + console.log(fetchedInvitedList) + }, [setFetchedInvitedList]); - const findFromKey = useCallback((list, target) => { + const findFromId = useCallback((list, target) => { for (let element of list) { - if (element.key == target) + if (element.DoDID == target) return element; } return null; }, []); const addList = useCallback((key, dataState, listState, source) => { - const listElement = findFromKey(source, key); + const listElement = findFromId(source, key); if (!listElement) return; listState(list => [...list, listElement]); @@ -279,11 +268,13 @@ function MemoForm(props) { mode="multiple" bordered={false} value={addUser.length !== 0 ? addUser : undefined} + onFocus={fetchInvited} onChange={setAddUser} > - {additionUser.map((item) => ( - - {item.rank} {item.name} + {fetchedInvitedList.map((item) => ( + item.DoDID && + + {'' + item.Rank + ' ' + item.Name} ))} @@ -293,7 +284,7 @@ function MemoForm(props) { icon={} onClick={() => { if (addUser.length !== 0) - addUser.forEach(({ key }) => addList(key, setAddUser, setAddUserList, additionUser)); + addUser.forEach(({ key }) => addList(key, setAddUser, setAddUserList, fetchedInvitedList)); }} />
From 83574d08779b89d2e803658a562cff2863278ab1 Mon Sep 17 00:00:00 2001 From: Yunseong Choe <68419358+marunemo@users.noreply.github.com> Date: Fri, 21 Oct 2022 06:06:58 +0000 Subject: [PATCH 23/48] [Feat]Fetch user list by keyword searching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 키워드를 입력하면 그에 해당하는 계급이나 이름으로 검색 --- back-end/controllers/userControllers.js | 17 +- front-end/web-next/componenets/MemoForm.js | 174 +++++++++++---------- 2 files changed, 106 insertions(+), 85 deletions(-) diff --git a/back-end/controllers/userControllers.js b/back-end/controllers/userControllers.js index 6e8c6204..3b78dd6f 100644 --- a/back-end/controllers/userControllers.js +++ b/back-end/controllers/userControllers.js @@ -40,11 +40,20 @@ const allUsers = asyncHandler(async (req, res) => { return (ranks.indexOf(b.Rank) + (b.is_registered ? 0 : 100)) - (ranks.indexOf(a.Rank) + (a.is_registered ? 0 : 100)); }); const index = req.query.index; - if (index) { - res.send(users.slice(parseInt(index) * 4, parseInt(index) * 4 + 4)); - } else if (keyword) { - let user = await User.find({ _id: { $eq: keyword }}, {password: 0}) + // if (index) { + // res.send(users.slice(parseInt(index) * 4, parseInt(index) * 4 + 4)); + // } else if (keyword) { + // let user = await User.find({ _id: { $eq: keyword }}, {password: 0}) + // res.send(user); //.find({ _id: { $ne: req.user._id } })); + // } else { + // res.status(400); + // throw new Error("잘못된 요청입니다."); + // } + if (keyword) { + let user = await User.find({ $or: [{ Name: { $regex: keyword, $options: 'i' } }, { Rank: { $regex: keyword, $options: 'i' } }] }, { password: 0 }) res.send(user); //.find({ _id: { $ne: req.user._id } })); + } else if (index) { + res.send(users.slice(parseInt(index) * 4, parseInt(index) * 4 + 4)); } else { res.status(400); throw new Error("잘못된 요청입니다."); diff --git a/front-end/web-next/componenets/MemoForm.js b/front-end/web-next/componenets/MemoForm.js index cf036e0f..76833035 100644 --- a/front-end/web-next/componenets/MemoForm.js +++ b/front-end/web-next/componenets/MemoForm.js @@ -153,7 +153,7 @@ function MemoForm(props) { const [memoContent, setMemoContent] = useState(''); const [fetchedInvitedList, setFetchedInvitedList] = useState([]); - const fetchInvited = useCallback(async() => { + const fetchInvited = useCallback(async () => { await fetch(process.env.NEXT_PUBLIC_BACKEND_ROOT + 'api/user?index=0', { 'method': 'GET', 'headers': { @@ -161,9 +161,20 @@ function MemoForm(props) { 'authorization': `Bearer ${getCookie('usercookie')}` } }) - .then(response => response.json()) - .then(data => setFetchedInvitedList(data)) - console.log(fetchedInvitedList) + .then(response => response.json()) + .then(data => setFetchedInvitedList(data)) + }, [setFetchedInvitedList]); + + const fetchInvitedFromKeyword = useCallback(async (keyword) => { + await fetch(process.env.NEXT_PUBLIC_BACKEND_ROOT + 'api/user?search=' + keyword, { + 'method': 'GET', + 'headers': { + 'content-type': 'application/json', + 'authorization': `Bearer ${getCookie('usercookie')}` + } + }) + .then(response => response.json()) + .then(data => setFetchedInvitedList(data)) }, [setFetchedInvitedList]); const findFromId = useCallback((list, target) => { @@ -205,76 +216,40 @@ function MemoForm(props) { >
-
-

제목

- setMemoTitle(event.target.value)} - /> -
-
-

보고 종류

- -
-
-

보고 체계

- -
- { - reportOrgList.length !== 0 &&
-

보고 인원

- {reportOrgList.map((org) => linkedUnit(org.list, org.key, () => deleteList(setReportOrgList, org.key)))} +

제목

+ setMemoTitle(event.target.value)} + /> +
+
+

보고 종류

+
- } -
-
-

추가 인원

+
+

보고 체계

@@ -283,25 +258,62 @@ function MemoForm(props) { shape="circle" icon={} onClick={() => { - if (addUser.length !== 0) - addUser.forEach(({ key }) => addList(key, setAddUser, setAddUserList, fetchedInvitedList)); + if (reportOrg.length !== 0) + reportOrg.forEach(({ key }) => addList(key, setReportOrg, setReportOrgList, orgType)); }} />
{ - addUserList.length !== 0 && - addUserList.map((user, index) => additionalPerson(user, index, () => deleteList(setAddUserList, user.key))) + reportOrgList.length !== 0 && +
+

보고 인원

+ {reportOrgList.map((org) => linkedUnit(org.list, org.key, () => deleteList(setReportOrgList, org.key)))} +
} -
-
-

내용

- -
+
+
+

추가 인원

+ +
+ { + addUserList.length !== 0 && + addUserList.map((user, index) => additionalPerson(user, index, () => deleteList(setAddUserList, user.key))) + } +
+
+

내용

+ +
From 097acc2981dc37bf96fbb353a36a88a383e217d5 Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Fri, 21 Oct 2022 08:14:44 +0000 Subject: [PATCH 24/48] [Feat]: #108 user encryption/decryption function completed --- .../web-next/encryption/userencryption.js | 34 ++++++++----------- front-end/web-next/pages/home.js | 7 ++-- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/front-end/web-next/encryption/userencryption.js b/front-end/web-next/encryption/userencryption.js index de7de927..f886ecd3 100644 --- a/front-end/web-next/encryption/userencryption.js +++ b/front-end/web-next/encryption/userencryption.js @@ -1,6 +1,5 @@ const { SecretClient } = require("@azure/keyvault-secrets"); const { ClientSecretCredential } = require("@azure/identity"); -const { CryptoJS } = require("crypto-js") var SHA256 = require("crypto-js/sha256"); var enc = require("crypto-js/enc-hex"); var enc2 = require('crypto-js/enc-utf8') @@ -30,32 +29,27 @@ function generateKey(IV){ } export async function encryptuser(id, plaintext) { - + let secret = null try { //secret exists - console.log(plaintext) - const secret = await client.getSecret(id); - console.log('secret exists') - - - let ciphertext = AES.encrypt(plaintext, secret.value).toString() - //return ciphertext - let bytes = AES.decrypt(ciphertext.toString(), secret.value) - return hex_to_ascii(bytes.toString(enc2.Utf8)) - - //console.log(originalText) + secret = await client.getSecret(id); } catch { //make new secret let key = generateKey(uuidv4()) let parsedkey = key.toString(enc.Hex) - const result = await client.setSecret(id, parsedkey); - //console.log(result) - + secret = await client.setSecret(id, parsedkey); } - - return 'hi' - + let ciphertext = AES.encrypt(plaintext, secret.value).toString() + return ciphertext } -export async function decryptuser(ciphertext, id) { +export async function decryptuser(id, ciphertext) { + let secret = null + try { //secret exists + secret = await client.getSecret(id); + } catch { //make new secret + return "unable to decrypt, id doesn't exist" + } + let bytes = AES.decrypt(ciphertext.toString(), secret.value) + return hex_to_ascii(bytes.toString(enc2.Utf8)) } \ No newline at end of file diff --git a/front-end/web-next/pages/home.js b/front-end/web-next/pages/home.js index d9d5c96f..bd3bb002 100644 --- a/front-end/web-next/pages/home.js +++ b/front-end/web-next/pages/home.js @@ -3,11 +3,10 @@ import style from '../styles/homepage.module.css' import Image from 'next/image' import unitlogo from '../img/unitlogo.png' import { Descriptions, Tabs, Avatar, List, PageHeader, Button, Input, Space } from 'antd'; -import {encryptuser} from '../encryption/userencryption' +import {decryptuser, encryptuser} from '../encryption/userencryption' import { jwtVerify } from 'jose'; -encryptuser('test1', 'hfipoawefjapoiwfhawpoeifjwf') const { Search } = Input; let onSearch = async (event) => { } @@ -111,7 +110,9 @@ const Home = (props) => { export async function getServerSideProps(context) { - + // let ciphertext = await encryptuser('test133', 'hfipoawefjapoiwfhawpoeifjwf') + // let decrypt = await decryptuser('test133', ciphertext) + // console.log(decrypt) const backendroot = process.env.NEXT_PUBLIC_BACKEND_ROOT const endpoint = backendroot + 'api/user?search=' const secret = process.env.JWT_SECRET From 34ef2e2cede8801058d2cfca1dec39339e0fe148 Mon Sep 17 00:00:00 2001 From: Yunseong Choe <68419358+marunemo@users.noreply.github.com> Date: Fri, 21 Oct 2022 10:55:21 +0000 Subject: [PATCH 25/48] [Feat]Activate memo submit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 메모 보고 작성 활성화 --- back-end/controllers/reportControllers.js | 71 ++++++++----- back-end/routes/reportRoutes.js | 4 +- front-end/web-next/componenets/MemoForm.js | 112 ++++++++++++--------- 3 files changed, 115 insertions(+), 72 deletions(-) diff --git a/back-end/controllers/reportControllers.js b/back-end/controllers/reportControllers.js index 1b631333..3162d41f 100644 --- a/back-end/controllers/reportControllers.js +++ b/back-end/controllers/reportControllers.js @@ -2,9 +2,25 @@ const asyncHandler = require("express-async-handler"); const Report = require("../models/reportModel"); const Reportsys = require("../models/reportModel"); const UnitM = require("../models/unitModel"); -const UserM = require("../models/unitModel"); +const UserM = require("../models/userModel"); const getScore = require('../ai/classifier.js') var mongoose = require('mongoose'); +const jwt = require("jsonwebtoken"); + +//@description Get report cards +//@route GET /api/report?index= +//@access Protected +const getReportCard = asyncHandler(async (req, res) => { + const { index } = req.query; + + if (!index) { + res.status(400); + throw new Error("잘못된 요청입니다."); + } + + let reportCards = await new Report({}, { password: 0 }); + res.send(reportCards.at(index)); +}); //@description Create new report card //@route POST /api/report @@ -15,7 +31,8 @@ const addReportCard = asyncHandler(async (req, res) => { ReportingSystem, Invited, Content, - Title + Title, + UserToken } = req.body; if (!Type || !ReportingSystem || !Invited || !Content || !Title) { @@ -23,41 +40,48 @@ const addReportCard = asyncHandler(async (req, res) => { throw new Error("모든 정보를 입력하세요."); } - User = req.user._id - Unit = req.user.Unit._id; - Severity = await getScore(Content) + //decodes token id + const decoded = jwt.verify(UserToken, process.env.JWT_SECRET); + const currentUser = await UserM.findById(decoded.id).select("-password"); + + let currentUnit = currentUser.Unit + let Severity = await getScore(Content) const report = await Report.create({ - User, + User: currentUser, Type, ReportingSystem, Invited, Content, Title, Severity, - Unit + Unit: currentUnit }); + + res.status(201).send(report); + return; + const editUnit = await UnitM.findByIdAndUpdate( - Unit, { - $push: { - reportCards: report._id - }, - }, { - new: true, - } + UnitId, { + $push: { + reportCards: report._id + }, + }, { + new: true, + } ) const editUser = await UserM.findByIdAndUpdate( - req.user._id, { - $push: { - myReportCards: report._id - }, - }, { - new: true, - } + UserId, { + $push: { + myReportCards: report._id + }, + }, { + new: true, + } ) - if (editReport && editUnit && editUser) { + if (editUnit && editUser) { res.status(201).send(report); } else { res.status(400); @@ -66,5 +90,6 @@ const addReportCard = asyncHandler(async (req, res) => { }); module.exports = { - addReportCard + addReportCard, + getReportCard }; diff --git a/back-end/routes/reportRoutes.js b/back-end/routes/reportRoutes.js index 7faaa2b4..7872aa03 100644 --- a/back-end/routes/reportRoutes.js +++ b/back-end/routes/reportRoutes.js @@ -1,6 +1,7 @@ const express = require("express"); const { - addReportCard + addReportCard, + getReportCard } = require("../controllers/reportControllers"); const { protect @@ -9,5 +10,6 @@ const { const router = express.Router(); router.route("/").post(protect, addReportCard); +router.route("/").get(protect, getReportCard); module.exports = router; diff --git a/front-end/web-next/componenets/MemoForm.js b/front-end/web-next/componenets/MemoForm.js index 76833035..eb37a6db 100644 --- a/front-end/web-next/componenets/MemoForm.js +++ b/front-end/web-next/componenets/MemoForm.js @@ -7,48 +7,48 @@ import styles from '../styles/MemoForm.module.css'; const orgType = [ { key: 0, - name: '당직계통', + title: '당직계통', list: [ { - key: 0, - avatar: "https://joeschmoe.io/api/v1/random", - name: 'OOO', - rank: '상사', - position: '당직사관', + DoDID: 0, + pic: "https://joeschmoe.io/api/v1/random", + Name: 'OOO', + Rank: '상사', + Position: '당직사관', }, { - key: 1, - avatar: "https://joeschmoe.io/api/v1/random", - name: 'XXX', - rank: '대위', - position: '당직사령', + DoDID: 1, + pic: "https://joeschmoe.io/api/v1/random", + Name: 'XXX', + Rank: '대위', + Position: '당직사령', } ] }, { key: 1, - name: '3중대', + title: '3중대', list: [ { - key: 0, - avatar: "https://joeschmoe.io/api/v1/random", - name: 'OOO', - rank: '소위', - position: '3중대 1소대장', + DoDID: 0, + pic: "https://joeschmoe.io/api/v1/random", + Name: 'OOO', + Rank: '소위', + Position: '3중대 1소대장', }, { - key: 1, - avatar: "https://joeschmoe.io/api/v1/random", - name: 'XXX', - rank: '상사', - position: '3중대 행정보급관', + DoDID: 1, + pic: "https://joeschmoe.io/api/v1/random", + Name: 'XXX', + Rank: '상사', + Position: '3중대 행정보급관', }, { - key: 2, - avatar: "https://joeschmoe.io/api/v1/random", - name: 'XOX', - rank: '대위', - position: '3중대장', + DoDID: 2, + pic: "https://joeschmoe.io/api/v1/random", + Name: 'XOX', + Rank: '대위', + Position: '3중대장', } ] } @@ -157,7 +157,7 @@ function MemoForm(props) { await fetch(process.env.NEXT_PUBLIC_BACKEND_ROOT + 'api/user?index=0', { 'method': 'GET', 'headers': { - 'content-type': 'application/json', + 'Content-Type': 'application/json', 'authorization': `Bearer ${getCookie('usercookie')}` } }) @@ -169,24 +169,47 @@ function MemoForm(props) { await fetch(process.env.NEXT_PUBLIC_BACKEND_ROOT + 'api/user?search=' + keyword, { 'method': 'GET', 'headers': { - 'content-type': 'application/json', + 'Content-Type': 'application/json', 'authorization': `Bearer ${getCookie('usercookie')}` } }) - .then(response => response.json()) - .then(data => setFetchedInvitedList(data)) + .then(response => response.json()) + .then(data => setFetchedInvitedList(data)) }, [setFetchedInvitedList]); + + const submitMemo = useCallback(async(memoTitle, memoType, reportOrgList, addUserList, memoContent) => { + const submitData = { + Title: memoTitle, + Type: memoType, + ReportingSystem: reportOrgList.map((org) => (org.title)), + Invited: addUserList, + Content: memoContent, + UserToken: getCookie('usercookie') + } + + await fetch(process.env.NEXT_PUBLIC_BACKEND_ROOT + 'api/report/', { + 'method': 'POST', + 'headers': { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': `Bearer ${getCookie('usercookie')}` + }, + 'body': JSON.stringify(submitData) + }) + .then(res => console.log(res)) + .catch(err => console.log(err)) +}, []); - const findFromId = useCallback((list, target) => { + const findFromId = useCallback((list, target, id) => { for (let element of list) { - if (element.DoDID == target) + if (element[id] == target) return element; } return null; }, []); - const addList = useCallback((key, dataState, listState, source) => { - const listElement = findFromId(source, key); + const addList = useCallback((key, id, dataState, listState, source) => { + const listElement = findFromId(source, key, id); if (!listElement) return; listState(list => [...list, listElement]); @@ -197,19 +220,12 @@ function MemoForm(props) { listState(list => list.filter(e => (e.key !== key))); }, []); - const submitMemo = useCallback((memoTitle, memoType, reportOrgList, addUserList, memoContent) => ({ - title: memoTitle, - type: memoType, - reportUnit: reportOrgList, - additionUnit: addUserList, - content: memoContent - }), []); return ( { - console.log(submitMemo(memoTitle, memoType, reportOrgList, addUserList, memoContent)); + submitMemo(memoTitle, memoType, reportOrgList, addUserList, memoContent); props.onSubmitted(); }} onCancel={props.onCancel} @@ -248,8 +264,8 @@ function MemoForm(props) { onChange={setReportOrg} > {orgType.map((item) => ( - - {item.name} + + {item.title} ))} @@ -259,7 +275,7 @@ function MemoForm(props) { icon={} onClick={() => { if (reportOrg.length !== 0) - reportOrg.forEach(({ key }) => addList(key, setReportOrg, setReportOrgList, orgType)); + reportOrg.forEach(({ key }) => addList(key, 'key', setReportOrg, setReportOrgList, orgType)); }} />
@@ -283,7 +299,7 @@ function MemoForm(props) { onChange={setAddUser} onSearch={fetchInvitedFromKeyword} > - {fetchedInvitedList.map((item) => ( + {fetchedInvitedList?.map((item) => ( item.DoDID && {'' + item.Rank + ' ' + item.Name} @@ -296,7 +312,7 @@ function MemoForm(props) { icon={} onClick={() => { if (addUser.length !== 0) - addUser.forEach(({ key }) => addList(key, setAddUser, setAddUserList, fetchedInvitedList)); + addUser.forEach(({ key }) => addList(key, 'DoDID', setAddUser, setAddUserList, fetchedInvitedList)); }} />
From 1775cf1b9653890b2cca6064362aa006b0347b70 Mon Sep 17 00:00:00 2001 From: Yunseong Choe <68419358+marunemo@users.noreply.github.com> Date: Fri, 21 Oct 2022 11:33:59 +0000 Subject: [PATCH 26/48] [Feat]Enable to fetch memo data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 메모 보고 내용 읽기 구현 --- back-end/controllers/reportControllers.js | 14 +- front-end/web-next/componenets/MemoReport.js | 8 +- front-end/web-next/pages/memonote.js | 223 ++++++++++--------- 3 files changed, 129 insertions(+), 116 deletions(-) diff --git a/back-end/controllers/reportControllers.js b/back-end/controllers/reportControllers.js index 3162d41f..b1786cc3 100644 --- a/back-end/controllers/reportControllers.js +++ b/back-end/controllers/reportControllers.js @@ -7,19 +7,13 @@ const getScore = require('../ai/classifier.js') var mongoose = require('mongoose'); const jwt = require("jsonwebtoken"); -//@description Get report cards -//@route GET /api/report?index= +//@description Get all report cards +//@route GET /api/report //@access Protected const getReportCard = asyncHandler(async (req, res) => { - const { index } = req.query; - if (!index) { - res.status(400); - throw new Error("잘못된 요청입니다."); - } - - let reportCards = await new Report({}, { password: 0 }); - res.send(reportCards.at(index)); + let reportCards = await Report.find({}); + res.send(reportCards); }); //@description Create new report card diff --git a/front-end/web-next/componenets/MemoReport.js b/front-end/web-next/componenets/MemoReport.js index e0284ebd..edab0317 100644 --- a/front-end/web-next/componenets/MemoReport.js +++ b/front-end/web-next/componenets/MemoReport.js @@ -39,10 +39,10 @@ function ReportList(props) { renderItem={(item) => ( )} diff --git a/front-end/web-next/pages/memonote.js b/front-end/web-next/pages/memonote.js index 432e25cc..73106fec 100644 --- a/front-end/web-next/pages/memonote.js +++ b/front-end/web-next/pages/memonote.js @@ -1,7 +1,8 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import Head from 'next/head' import { Layout, Row, Col, List, Button, Input, Divider, Select } from 'antd'; import { FormOutlined } from '@ant-design/icons'; +import { getCookie } from 'cookies-next'; import ReportLayout from '../componenets/MemoReport'; import MemoForm from '../componenets/MemoForm'; import Styles from '../styles/MemoLayout.module.css'; @@ -10,6 +11,19 @@ export default function Memo() { const [selectedItem, setSelection] = useState(undefined); const [memonoteType, setMemonoteType] = useState('받은 메모 보고'); const [formOpened, setFormOpened] = useState(false); + const [memoRenderList, setMemoRenderList] = useState([]); + + useEffect(() => { + fetch(process.env.NEXT_PUBLIC_BACKEND_ROOT + 'api/report/', { + 'method': 'GET', + 'headers': { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${getCookie('usercookie')}` + } + }) + .then(response => response.json()) + .then(data => setMemoRenderList(data)); + }, []) const sampleData = [ { @@ -50,17 +64,17 @@ export default function Memo() { return (

- {props.title} - {props.isDone ? ' [종결]' : ' [미종결]'} + {props.Title} + {props.Status === 'Unresolved' ? ' [미종결]' : ' [종결]'}

- 종류: {props.type} - 중요도: {props.level} - {props.datetime} + 종류: {props.Type} + 중요도: {props.Severity} + {props.createdAt}
@@ -70,7 +84,7 @@ export default function Memo() { function Footer(props) { return (

- 보고 체계: {props.unit} + 보고 체계: {props.reportingSystem}

) } @@ -80,104 +94,109 @@ export default function Memo() { 메모 보고 - - -
-
- - -
- -
- - -
- -
- ( -
-
+ +
+ ( +
+ +
- - 중요도: {item.level} - {item.datetime} - - - -
- )} - /> -
-
-
- - { - (selectedItem !== undefined) && -
- +
+
+ + + { + selectedItem !== undefined && +
+ + } + footer={ +
+ } + height="710px" + name={memoRenderList[selectedItem].User?.Name} + position={memoRenderList[selectedItem].User?.Position} + memo={memoRenderList[selectedItem].Content} + datetime={memoRenderList[selectedItem].createdAt} + comment={memoRenderList[selectedItem].Comment} /> - } - footer={ -
- } - height="710px" - name={sampleData[selectedItem].name} - position={sampleData[selectedItem].position} - memo={sampleData[selectedItem].memo} - datetime={sampleData[selectedItem].datetime} - comment={sampleData[selectedItem].comment} - /> -
- } -
- +
+ } + + + ) + } setFormOpened(false)} From 14e2a179c6832e7af2e0947e43779cc8477d0461 Mon Sep 17 00:00:00 2001 From: Yunseong Choe <68419358+marunemo@users.noreply.github.com> Date: Fri, 21 Oct 2022 11:43:33 +0000 Subject: [PATCH 27/48] [Fix]Roll-back props field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 잘못 수정된 props의 field를 되돌림 --- front-end/web-next/pages/memonote.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/front-end/web-next/pages/memonote.js b/front-end/web-next/pages/memonote.js index 73106fec..adffb261 100644 --- a/front-end/web-next/pages/memonote.js +++ b/front-end/web-next/pages/memonote.js @@ -64,17 +64,17 @@ export default function Memo() { return (

- {props.Title} - {props.Status === 'Unresolved' ? ' [미종결]' : ' [종결]'} + {props.title} + {props.status === 'Unresolved' ? ' [미종결]' : ' [종결]'}

- 종류: {props.Type} - 중요도: {props.Severity} - {props.createdAt} + 종류: {props.type} + 중요도: {props.level} + {props.datetime}
@@ -178,7 +178,7 @@ export default function Memo() { type={memoRenderList[selectedItem].Type} level={memoRenderList[selectedItem].Severity} datetime={memoRenderList[selectedItem].createdAt} - isDone={memoRenderList[selectedItem].Status} + status={memoRenderList[selectedItem].Status} /> } footer={ From 12853a1767cebf14737b0d4c1506924d34ed4b87 Mon Sep 17 00:00:00 2001 From: Yunseong Choe <68419358+marunemo@users.noreply.github.com> Date: Fri, 21 Oct 2022 11:53:23 +0000 Subject: [PATCH 28/48] [Design]Create spinner for loading state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 로딩 상태라는 것을 보여주기 위한 spinner 생성 --- front-end/web-next/pages/memonote.js | 207 +++++++++--------- .../web-next/styles/MemoLayout.module.css | 7 +- front-end/web-next/styles/globals.css | 4 + 3 files changed, 119 insertions(+), 99 deletions(-) diff --git a/front-end/web-next/pages/memonote.js b/front-end/web-next/pages/memonote.js index adffb261..d626c9b2 100644 --- a/front-end/web-next/pages/memonote.js +++ b/front-end/web-next/pages/memonote.js @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react'; import Head from 'next/head' -import { Layout, Row, Col, List, Button, Input, Divider, Select } from 'antd'; +import { Layout, Row, Col, List, Button, Input, Divider, Select, Spin } from 'antd'; import { FormOutlined } from '@ant-design/icons'; import { getCookie } from 'cookies-next'; import ReportLayout from '../componenets/MemoReport'; @@ -95,107 +95,118 @@ export default function Memo() { 메모 보고 { - memoRenderList.length !== 0 && - ( - - -
-
- - -
- -
- - -
- -
- ( -
+ + + + + ) + : ( + + +
+
+ + +
+ +
+ +
+ +
+ ( +
+ - -
- )} - /> -
-
-
- - { - selectedItem !== undefined && -
- - } - footer={ -
- } - height="710px" - name={memoRenderList[selectedItem].User?.Name} - position={memoRenderList[selectedItem].User?.Position} - memo={memoRenderList[selectedItem].Content} - datetime={memoRenderList[selectedItem].createdAt} - comment={memoRenderList[selectedItem].Comment} - /> +
+ {item.Title} + {item.Status === 'Unresolved' ? ' [미종결]' : ' [종결]'} +
+
+ {item.Content} +
+ + 중요도: {item.Severity} + {item.createdAt} + + + +
+ )} + /> +
- } - - - ) + + + { + selectedItem !== undefined && +
+ + } + footer={ +
+ } + height="710px" + name={memoRenderList[selectedItem].User?.Name} + position={memoRenderList[selectedItem].User?.Position} + memo={memoRenderList[selectedItem].Content} + datetime={memoRenderList[selectedItem].createdAt} + comment={memoRenderList[selectedItem].Comment} + /> +
+ } +
+ + ) } .ant-select-arrow { color: #000; +} + +.ant-spin-dot-item { + background-color: #008080; } \ No newline at end of file From a661c97b48e71df7c0e6f054d44cfd196fdc167e Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Fri, 21 Oct 2022 13:43:19 +0000 Subject: [PATCH 29/48] [Feat]: #110 sidebar completed --- front-end/web-next/componenets/MenuLayout.js | 2 +- front-end/web-next/firebaseauth.js | 27 + front-end/web-next/package-lock.json | 2000 ++++++++++++++++-- front-end/web-next/package.json | 2 + front-end/web-next/pages/messages.js | 69 +- front-end/web-next/styles/chat.module.css | 41 + front-end/web-next/styles/globals.css | 8 + 7 files changed, 2027 insertions(+), 122 deletions(-) create mode 100644 front-end/web-next/firebaseauth.js create mode 100644 front-end/web-next/styles/chat.module.css diff --git a/front-end/web-next/componenets/MenuLayout.js b/front-end/web-next/componenets/MenuLayout.js index 27d64d8a..a322767b 100644 --- a/front-end/web-next/componenets/MenuLayout.js +++ b/front-end/web-next/componenets/MenuLayout.js @@ -28,7 +28,7 @@ function MenuLayout(props) { label: 메모 보고 }, { - key: 'messeges', + key: 'messages', icon: , label: 메세지 }, diff --git a/front-end/web-next/firebaseauth.js b/front-end/web-next/firebaseauth.js new file mode 100644 index 00000000..ffd30858 --- /dev/null +++ b/front-end/web-next/firebaseauth.js @@ -0,0 +1,27 @@ +// Import the functions you need from the SDKs you need +import { initializeApp } from "firebase/app"; +import { getFirestore } from "firebase/firestore"; + +import { getAnalytics } from "firebase/analytics"; +// TODO: Add SDKs for Firebase products that you want to use +// https://firebase.google.com/docs/web/setup#available-libraries + +// Your web app's Firebase configuration +// For Firebase JS SDK v7.20.0 and later, measurementId is optional +const firebaseConfig = { + apiKey: "AIzaSyBanpq8RSFEdjeLuPLFLxP5SSSaRiuQt_Q", + authDomain: "roka-srs.firebaseapp.com", + projectId: "roka-srs", + storageBucket: "roka-srs.appspot.com", + messagingSenderId: "507147817796", + appId: "1:507147817796:web:322e5dd0bd63c0dc033d11", + measurementId: "G-2TFC1LHNV0" +}; + +// Initialize Firebase +console.log(getFirestore) +const app = initializeApp(firebaseConfig); +const db = getFirestore() +//const analytics = getAnalytics(app); + +export {db} \ No newline at end of file diff --git a/front-end/web-next/package-lock.json b/front-end/web-next/package-lock.json index d10c1b97..72114e01 100644 --- a/front-end/web-next/package-lock.json +++ b/front-end/web-next/package-lock.json @@ -19,12 +19,14 @@ "cookies-next": "^2.1.1", "crypto-js": "^4.1.1", "cryptojs": "^2.5.3", + "firebase": "^9.12.1", "formik-antd": "^2.0.4", "jose": "^4.10.0", "next": "^12.3.1", "react": "18.2.0", "react-dom": "18.2.0", "react-draggable": "^4.4.5", + "react-firebase-hooks": "^5.0.3", "react-icons": "^4.4.0", "react-infinite-scroll-component": "^6.1.0", "react-organizational-chart": "^2.2.0", @@ -887,6 +889,636 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@firebase/analytics": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.8.3.tgz", + "integrity": "sha512-viGhc57JW9zHp/0JKpLBUthdpOrEjbPETQFz8oNfaNma+cHA6FtIrtg4Sla52DgqatbATcE9aIDBiPCGrCtNjw==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/installations": "0.5.15", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/analytics-compat": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.1.16.tgz", + "integrity": "sha512-mDAhE33WiyCrqSQZvzyZtQCCdf4ipn5tsEpTbIUruk7MbThQ1EbNAbPBiEk9NDLD3sUyLABZGFctvym/hc8H+w==", + "dependencies": { + "@firebase/analytics": "0.8.3", + "@firebase/analytics-types": "0.7.0", + "@firebase/component": "0.5.20", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/analytics-types": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.7.0.tgz", + "integrity": "sha512-DNE2Waiwy5+zZnCfintkDtBfaW6MjIG883474v6Z0K1XZIvl76cLND4iv0YUb48leyF+PJK1KO2XrgHb/KpmhQ==" + }, + "node_modules/@firebase/app": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.8.2.tgz", + "integrity": "sha512-ByNDCe8h9O/szO3XVTrS484MtqBOKriVaNCQC7Y7KgZSaiA0OOWmIY5vwi63mBTYetqMNN5VGiG/6ZSmGIZyoQ==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "idb": "7.0.1", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-check": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.5.15.tgz", + "integrity": "sha512-ifQalGXkXMwGR3F8Glmo1XtDg0UjkwCmI/ff05mxnKGMfs5ZDyw8DikQfna//a/KdYuOBqxlBwS2BhHiobqUUg==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/app-check-compat": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.2.15.tgz", + "integrity": "sha512-EgD1WEFwwq7aP7DxPSYuUpMt8eAhClA57976D3BaHDbH/IXEuw0DfaeT0LtBb+xJD7J8uxy+YKpudCC8gzUu8g==", + "dependencies": { + "@firebase/app-check": "0.5.15", + "@firebase/app-check-types": "0.4.0", + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.1.0.tgz", + "integrity": "sha512-uZfn9s4uuRsaX5Lwx+gFP3B6YsyOKUE+Rqa6z9ojT4VSRAsZFko9FRn6OxQUA1z5t5d08fY4pf+/+Dkd5wbdbA==" + }, + "node_modules/@firebase/app-check-types": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.4.0.tgz", + "integrity": "sha512-SsWafqMABIOu7zLgWbmwvHGOeQQVQlwm42kwwubsmfLmL4Sf5uGpBfDhQ0CAkpi7bkJ/NwNFKafNDL9prRNP0Q==" + }, + "node_modules/@firebase/app-compat": { + "version": "0.1.37", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.1.37.tgz", + "integrity": "sha512-doTKYGlVc8ZiQNOl66rpkU/YItRyOxCgMp4YWThXkPM4T/pTi4a9IMCe8K88gVNeYWd8sKW4vSnxjcOG5hQXEA==", + "dependencies": { + "@firebase/app": "0.8.2", + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.8.0.tgz", + "integrity": "sha512-Lec3VVquUwXPn2UReGSsfTxuMBVRmzGIwA/CJnF0LQuPgv9kOmXk9mVqsDMfHxHtqjai0n6wWHR2TqjdVV/bYA==" + }, + "node_modules/@firebase/auth": { + "version": "0.20.10", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-0.20.10.tgz", + "integrity": "sha512-uAZypmVv/4nijaPVtR/ipjKBmSDPLQ7sNScLHs2DVhdvCklgUUF5+zsEdPlMfKDIfmVQHFwHbUgeKyXDYSRMwQ==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "node-fetch": "2.6.7", + "selenium-webdriver": "4.1.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/auth-compat": { + "version": "0.2.23", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.2.23.tgz", + "integrity": "sha512-r9YEXaL7YKoFOWHRvVoQ6d5klP+hkSsAtt21UIvP3/BxDDU+yLXN5vVvFHr38apuUeMGN34M7zkY6SihnLutIQ==", + "dependencies": { + "@firebase/auth": "0.20.10", + "@firebase/auth-types": "0.11.0", + "@firebase/component": "0.5.20", + "@firebase/util": "1.7.2", + "node-fetch": "2.6.7", + "selenium-webdriver": "4.1.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.1.6.tgz", + "integrity": "sha512-etIi92fW3CctsmR9e3sYM3Uqnoq861M0Id9mdOPF6PWIg38BXL5k4upCNBggGUpLIS0H1grMOvy/wn1xymwe2g==", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/auth-types": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.11.0.tgz", + "integrity": "sha512-q7Bt6cx+ySj9elQHTsKulwk3+qDezhzRBFC9zlQ1BjgMueUOnGMcvqmU0zuKlQ4RhLSH7MNAdBV2znVaoN3Vxw==", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/component": { + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.20.tgz", + "integrity": "sha512-wP51tQBlPFprfAWxWjzC/56hG4APhl43jFsgwuqCl3bhVbiKcr278QbrbGNmIXDeGKo4sGZLAnH9whl2apeCmA==", + "dependencies": { + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.13.9.tgz", + "integrity": "sha512-raQEBgQQybaEoMloJL8wWHQywGQ9mF2VbitvHydsbSNn+KL/xRDjXeQZPuuSbRjkYV6mR8jvQB7gpnzQQNE8Qg==", + "dependencies": { + "@firebase/auth-interop-types": "0.1.6", + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.2.9.tgz", + "integrity": "sha512-zzyFM3+jW/qYtHojiQirHXGXYyElbqVngEEn/i2gXoSzcK0Y2AL5oHAqGYXLaaW0+t4Zwnssh3HnQJM8C1D0fw==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/database": "0.13.9", + "@firebase/database-types": "0.9.16", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-types": { + "version": "0.9.16", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.9.16.tgz", + "integrity": "sha512-dK/uFgHisrVijSoHf9RLJ7NwvlOul2rO/z9ufOSbGd8/TqFVASXz+19mynhDIoSEnyQtJC/NTyBzSPfjz0w61w==", + "dependencies": { + "@firebase/app-types": "0.8.0", + "@firebase/util": "1.7.2" + } + }, + "node_modules/@firebase/firestore": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-3.7.1.tgz", + "integrity": "sha512-sDZ79cUf4cwCyRzN74zODgaeUvyt0lGA8YwaasVVqojgznwMG/bIz+/Tny4ZEnLZFrlniCqt2tStWsiC6s3u7g==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "@firebase/webchannel-wrapper": "0.8.0", + "@grpc/grpc-js": "^1.3.2", + "@grpc/proto-loader": "^0.6.13", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=10.10.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/firestore-compat": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.2.1.tgz", + "integrity": "sha512-XiiTpmUfyZ6QU3Dw9BCT4T+KPvqzada1GsUNX49HmriWHpIn3jTAjsagkigRAnmNDlxS3ki6Yzg9Cs60tpD0tw==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/firestore": "3.7.1", + "@firebase/firestore-types": "2.5.0", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/firestore-types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-2.5.0.tgz", + "integrity": "sha512-I6c2m1zUhZ5SH0cWPmINabDyH5w0PPFHk2UHsjBpKdZllzJZ2TwTkXbDtpHUZNmnc/zAa0WNMNMvcvbb/xJLKA==", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/functions": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.8.7.tgz", + "integrity": "sha512-JHSKdAOzlFJ9NdKoOaq4x6S1q6B3GmYZDg13KIDsE6BC0E9o/eWxOWOjSFJRCP/lpfFwa0rYBRayfUvZxW3BLw==", + "dependencies": { + "@firebase/app-check-interop-types": "0.1.0", + "@firebase/auth-interop-types": "0.1.6", + "@firebase/component": "0.5.20", + "@firebase/messaging-interop-types": "0.1.0", + "@firebase/util": "1.7.2", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/functions-compat": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.2.7.tgz", + "integrity": "sha512-bcUst8ZDJHeVy2Wox4KEM5EizsrrqLzbwFIwJD7KkuSYP8XrlV2gaqJnCvIXXc0Nc4JRGvbXcvFFMXDjhsEp4Q==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/functions": "0.8.7", + "@firebase/functions-types": "0.5.0", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/functions-types": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.5.0.tgz", + "integrity": "sha512-qza0M5EwX+Ocrl1cYI14zoipUX4gI/Shwqv0C1nB864INAD42Dgv4v94BCyxGHBg2kzlWy8PNafdP7zPO8aJQA==" + }, + "node_modules/@firebase/installations": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.5.15.tgz", + "integrity": "sha512-RVm2nc2d+bEDFzFzQDTTU1Z13fjAD0v88yDLjtRZuT2R7JwvAegQ4F7CupBvnnf7nftkd3kBwdOi8MhMthb3jQ==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/util": "1.7.2", + "idb": "7.0.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/installations-compat": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.1.15.tgz", + "integrity": "sha512-m0atyudsVj6ekmM+djhhzzInMC3Y233YJky9vXUVt5MHQY0mHhqDds9+UIrCa6cpbl+ntI2fOuoYV7y01s3sfw==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/installations": "0.5.15", + "@firebase/installations-types": "0.4.0", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/installations-types": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.4.0.tgz", + "integrity": "sha512-nXxWKQDvBGctuvsizbUEJKfxXU9WAaDhon+j0jpjIfOJkvkj3YHqlLB/HeYjpUn85Pb22BjplpTnDn4Gm9pc3A==", + "peerDependencies": { + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/logger": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.3.3.tgz", + "integrity": "sha512-POTJl07jOKTOevLXrTvJD/VZ0M6PnJXflbAh5J9VGkmtXPXNG6MdZ9fmRgqYhXKTaDId6AQenQ262uwgpdtO0Q==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/messaging": { + "version": "0.9.19", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.9.19.tgz", + "integrity": "sha512-xu99y/7/P+y3txGtgjsVJZyvx7T5/KdvFgDWS7oZwhKYG0o+DXFvvw3SBMK82LFGFOoyHlJUPqv45EyCPnOPCA==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/installations": "0.5.15", + "@firebase/messaging-interop-types": "0.1.0", + "@firebase/util": "1.7.2", + "idb": "7.0.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/messaging-compat": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.1.19.tgz", + "integrity": "sha512-h5tx4nxfSILeRquk5mKE8Onu7WtL6b7rfB6GKNJKecvkPs3nnq5Z4cp2Av4JUR2Wtt9UxCTfO0iRbbmtrt2bZQ==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/messaging": "0.9.19", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/messaging-interop-types": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.1.0.tgz", + "integrity": "sha512-DbvUl/rXAZpQeKBnwz0NYY5OCqr2nFA0Bj28Fmr3NXGqR4PAkfTOHuQlVtLO1Nudo3q0HxAYLa68ZDAcuv2uKQ==" + }, + "node_modules/@firebase/performance": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.5.15.tgz", + "integrity": "sha512-YnnkUehXXzqQefNE5PlPEsXeJYSeY7cMWEdHYTj6u0/F5ntLSAhVZC8jl3Y0fTU1W8a9USQhml6NaXyWiVGmjQ==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/installations": "0.5.15", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/performance-compat": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.1.15.tgz", + "integrity": "sha512-mryHr5eBEpWxBo8b3KM/53SwwVjMVahwdEnhfx1r+zAvmEPEzXUOGBzAC1l5WQ4DrwtDR87uMZ5soiQ/0jl9QQ==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/performance": "0.5.15", + "@firebase/performance-types": "0.1.0", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/performance-types": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.1.0.tgz", + "integrity": "sha512-6p1HxrH0mpx+622Ql6fcxFxfkYSBpE3LSuwM7iTtYU2nw91Hj6THC8Bc8z4nboIq7WvgsT/kOTYVVZzCSlXl8w==" + }, + "node_modules/@firebase/remote-config": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.3.14.tgz", + "integrity": "sha512-wEOz3Tasxhr5lCGioe0WNZwDOoQhNZK2qGAm5+AlHAPaAhWIWvqUTkKsk3nFRztyRZzj3r9k5Gc2OSpEcQKP1A==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/installations": "0.5.15", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/remote-config-compat": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.1.15.tgz", + "integrity": "sha512-jGUrZXIxQRMeSrqEaCi3MtMF33NN12TNTQDZlbex2+T2+yTMI/sn3Mq52T/OccCo86DK17WVlXSWQCH1zCD13g==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/remote-config": "0.3.14", + "@firebase/remote-config-types": "0.2.0", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/remote-config-types": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.2.0.tgz", + "integrity": "sha512-hqK5sCPeZvcHQ1D6VjJZdW6EexLTXNMJfPdTwbD8NrXUw6UjWC4KWhLK/TSlL0QPsQtcKRkaaoP+9QCgKfMFPw==" + }, + "node_modules/@firebase/storage": { + "version": "0.9.12", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.9.12.tgz", + "integrity": "sha512-XIAmje0ufvRrxrUU/9tvGCuUIy7WSJf3XM8Y8OV9EW2Dg1w4f8IpraLiUdlirdtFM0UAnO2kDQHoiVQYhRrADQ==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/util": "1.7.2", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/storage-compat": { + "version": "0.1.20", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.1.20.tgz", + "integrity": "sha512-8vruwltKdvEPhYbPXA/otb5fAD7MGsBHpCzktJWvF7eIALa4sUlYt+jJxG5Nwk2FoT1NrwLQ7TtI7zvm6/NinA==", + "dependencies": { + "@firebase/component": "0.5.20", + "@firebase/storage": "0.9.12", + "@firebase/storage-types": "0.6.0", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/storage-types": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.6.0.tgz", + "integrity": "sha512-1LpWhcCb1ftpkP/akhzjzeFxgVefs6eMD2QeKiJJUGH1qOiows2w5o0sKCUSQrvrRQS1lz3SFGvNR1Ck/gqxeA==", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/util": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.7.2.tgz", + "integrity": "sha512-P3aTihYEMoz2QQlcn0T7av7HLEK9gsTc1ZiN9VA8wnUtEJscUNemCmTmP3RRysqEb3Z+tVVoycztY8f6R36rRw==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/webchannel-wrapper": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.8.0.tgz", + "integrity": "sha512-Q8erQds5LuAUgNuFOt/tu/abffYUHYxN+Ogp2V5EOssfFG7Ja4ce324Sqyq41u/vB5CSr+tfYS3JzTDrDxCvdw==" + }, + "node_modules/@grpc/grpc-js": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.7.2.tgz", + "integrity": "sha512-MqqbVynbe3VUSnApFW/dpkDaa9T1ASqRnMWeSPGFO/Ro98R7XUDLacfeBa7RaSI1iFu9GYk5gBKARf0zipFe4w==", + "dependencies": { + "@grpc/proto-loader": "^0.7.0", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/grpc-js/node_modules/@grpc/proto-loader": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.3.tgz", + "integrity": "sha512-5dAvoZwna2Py3Ef96Ux9jIkp3iZ62TUsV00p3wVBPNX5K178UbNi8Q7gQVqwXT1Yq9RejIGG9G2IPEo93T6RcA==", + "dependencies": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^7.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/grpc-js/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/@grpc/grpc-js/node_modules/protobufjs": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz", + "integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@grpc/grpc-js/node_modules/protobufjs/node_modules/long": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.0.tgz", + "integrity": "sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w==" + }, + "node_modules/@grpc/grpc-js/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@grpc/grpc-js/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.6.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.13.tgz", + "integrity": "sha512-FjxPYDRTn6Ec3V0arm1FtSpmP6V50wuph2yILpyvTKzjc76oDdoihXqM1DzOW5ubvCC8GivfCnNtfaRE8myJ7g==", + "dependencies": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.11.3", + "yargs": "^16.2.0" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/proto-loader/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/@grpc/proto-loader/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@grpc/proto-loader/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.10.7", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", @@ -1253,6 +1885,60 @@ "node": ">= 8" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, "node_modules/@rushstack/eslint-patch": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", @@ -1289,6 +1975,11 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, "node_modules/@types/node": { "version": "16.11.65", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.65.tgz", @@ -1712,7 +2403,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, "license": "MIT" }, "node_modules/base64-js": { @@ -1743,7 +2433,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -1945,7 +2634,6 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, "license": "MIT" }, "node_modules/concurrently": { @@ -2034,6 +2722,11 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "node_modules/cosmiconfig": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", @@ -2816,6 +3509,17 @@ "reusify": "^1.0.4" } }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -2864,6 +3568,39 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/firebase": { + "version": "9.12.1", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-9.12.1.tgz", + "integrity": "sha512-sBp4rvkCC7TUnGeneRNs6GVcajO+iSXmYjxqXN4FsrBzldJ5/AOnDXf4bi9OUZtQSl+EHDgUWShBieht15ijgQ==", + "dependencies": { + "@firebase/analytics": "0.8.3", + "@firebase/analytics-compat": "0.1.16", + "@firebase/app": "0.8.2", + "@firebase/app-check": "0.5.15", + "@firebase/app-check-compat": "0.2.15", + "@firebase/app-compat": "0.1.37", + "@firebase/app-types": "0.8.0", + "@firebase/auth": "0.20.10", + "@firebase/auth-compat": "0.2.23", + "@firebase/database": "0.13.9", + "@firebase/database-compat": "0.2.9", + "@firebase/firestore": "3.7.1", + "@firebase/firestore-compat": "0.2.1", + "@firebase/functions": "0.8.7", + "@firebase/functions-compat": "0.2.7", + "@firebase/installations": "0.5.15", + "@firebase/installations-compat": "0.1.15", + "@firebase/messaging": "0.9.19", + "@firebase/messaging-compat": "0.1.19", + "@firebase/performance": "0.5.15", + "@firebase/performance-compat": "0.1.15", + "@firebase/remote-config": "0.3.14", + "@firebase/remote-config-compat": "0.1.15", + "@firebase/storage": "0.9.12", + "@firebase/storage-compat": "0.1.20", + "@firebase/util": "1.7.2" + } + }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -2951,7 +3688,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, "license": "ISC" }, "node_modules/function-bind": { @@ -3038,7 +3774,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -3190,6 +3925,11 @@ "react-is": "^16.7.0" } }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, "node_modules/http-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", @@ -3215,6 +3955,11 @@ "node": ">= 6" } }, + "node_modules/idb": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz", + "integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==" + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -3244,6 +3989,11 @@ "node": ">= 4" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3274,7 +4024,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -3583,6 +4332,11 @@ "node": ">=8" } }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3738,6 +4492,17 @@ "node": ">=4.0" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, "node_modules/jwa": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", @@ -3788,6 +4553,14 @@ "node": ">= 0.8.0" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -3820,6 +4593,11 @@ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "peer": true }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -3862,6 +4640,11 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -3939,7 +4722,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -4040,6 +4822,25 @@ } } }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", @@ -4160,7 +4961,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -4232,6 +5032,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4275,7 +5080,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -4359,6 +5163,11 @@ "node": ">= 0.8.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -4370,6 +5179,31 @@ "react-is": "^16.13.1" } }, + "node_modules/protobufjs": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -5030,6 +5864,15 @@ "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==", "peer": true }, + "node_modules/react-firebase-hooks": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/react-firebase-hooks/-/react-firebase-hooks-5.0.3.tgz", + "integrity": "sha512-0+V2XwInZJNjW8B2cm+U21Hlv4xnp/1tJqIoDg2rjyWzKTQ9VoLPQ9PAt+fMqPumjLz5uCIREY7YqGSSjc439Q==", + "peerDependencies": { + "firebase": ">= 9.0.0", + "react": ">= 16.8.0" + } + }, "node_modules/react-icons": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.4.0.tgz", @@ -5071,6 +5914,20 @@ "react-dom": ">= 16.12.0" } }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "node_modules/regenerator-runtime": { "version": "0.13.9", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", @@ -5161,7 +6018,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -5241,6 +6097,19 @@ "compute-scroll-into-view": "^1.0.17" } }, + "node_modules/selenium-webdriver": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.1.2.tgz", + "integrity": "sha512-e4Ap8vQvhipgBB8Ry9zBiKGkU6kHKyNnWiavGGLKkrdW81Zv7NVMtFOL/j3yX0G8QScM7XIXijKssNd4EUxSOw==", + "dependencies": { + "jszip": "^3.6.0", + "tmp": "^0.2.1", + "ws": ">=7.4.6" + }, + "engines": { + "node": ">= 10.15.0" + } + }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -5250,6 +6119,11 @@ "semver": "bin/semver.js" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, "node_modules/shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", @@ -5338,6 +6212,14 @@ "npm": ">=6" } }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/string-convert": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", @@ -5514,6 +6396,17 @@ "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", "peer": true }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -5540,6 +6433,11 @@ "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -5703,6 +6601,11 @@ "which-typed-array": "^1.1.2" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/uuid": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", @@ -5711,6 +6614,41 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5792,9 +6730,28 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, "license": "ISC" }, + "node_modules/ws": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", + "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -6401,121 +7358,649 @@ } } }, - "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "@babel/types": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", + "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, + "@ctrl/tinycolor": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz", + "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==" + }, + "@emotion/babel-plugin": { + "version": "11.10.2", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.2.tgz", + "integrity": "sha512-xNQ57njWTFVfPAc3cjfuaPdsgLp5QOSuRsj9MA6ndEhH/AzuZM86qIQzt6rq+aGBwj3n5/TkLmU5lhAfdRmogA==", + "requires": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/plugin-syntax-jsx": "^7.17.12", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/serialize": "^1.1.0", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.0.13" + } + }, + "@emotion/cache": { + "version": "11.10.3", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.3.tgz", + "integrity": "sha512-Psmp/7ovAa8appWh3g51goxu/z3iVms7JXOreq136D8Bbn6dYraPnmL6mdM8GThEx9vwSn92Fz+mGSjBzN8UPQ==", + "requires": { + "@emotion/memoize": "^0.8.0", + "@emotion/sheet": "^1.2.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "stylis": "4.0.13" + } + }, + "@emotion/css": { + "version": "11.10.0", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.10.0.tgz", + "integrity": "sha512-dH9f+kSCucc8ilMg0MUA1AemabcyzYpe5EKX24F528PJjD7HyIY/VBNJHxfUdc8l400h2ncAjR6yEDu+DBj2cg==", + "requires": { + "@emotion/babel-plugin": "^11.10.0", + "@emotion/cache": "^11.10.0", + "@emotion/serialize": "^1.1.0", + "@emotion/sheet": "^1.2.0", + "@emotion/utils": "^1.2.0" + } + }, + "@emotion/hash": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", + "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + }, + "@emotion/memoize": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + }, + "@emotion/serialize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.0.tgz", + "integrity": "sha512-F1ZZZW51T/fx+wKbVlwsfchr5q97iW8brAnXmsskz4d0hVB4O3M/SiA3SaeH06x02lSNzkkQv+n3AX3kCXKSFA==", + "requires": { + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/unitless": "^0.8.0", + "@emotion/utils": "^1.2.0", + "csstype": "^3.0.2" + } + }, + "@emotion/sheet": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.0.tgz", + "integrity": "sha512-OiTkRgpxescko+M51tZsMq7Puu/KP55wMT8BgpcXVG2hqXc0Vo0mfymJ/Uj24Hp0i083ji/o0aLddh08UEjq8w==" + }, + "@emotion/unitless": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", + "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + }, + "@emotion/utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", + "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + }, + "@emotion/weak-memoize": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", + "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + }, + "@eslint/eslintrc": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", + "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + } + }, + "@firebase/analytics": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.8.3.tgz", + "integrity": "sha512-viGhc57JW9zHp/0JKpLBUthdpOrEjbPETQFz8oNfaNma+cHA6FtIrtg4Sla52DgqatbATcE9aIDBiPCGrCtNjw==", + "requires": { + "@firebase/component": "0.5.20", + "@firebase/installations": "0.5.15", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "@firebase/analytics-compat": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.1.16.tgz", + "integrity": "sha512-mDAhE33WiyCrqSQZvzyZtQCCdf4ipn5tsEpTbIUruk7MbThQ1EbNAbPBiEk9NDLD3sUyLABZGFctvym/hc8H+w==", + "requires": { + "@firebase/analytics": "0.8.3", + "@firebase/analytics-types": "0.7.0", + "@firebase/component": "0.5.20", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "@firebase/analytics-types": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.7.0.tgz", + "integrity": "sha512-DNE2Waiwy5+zZnCfintkDtBfaW6MjIG883474v6Z0K1XZIvl76cLND4iv0YUb48leyF+PJK1KO2XrgHb/KpmhQ==" + }, + "@firebase/app": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.8.2.tgz", + "integrity": "sha512-ByNDCe8h9O/szO3XVTrS484MtqBOKriVaNCQC7Y7KgZSaiA0OOWmIY5vwi63mBTYetqMNN5VGiG/6ZSmGIZyoQ==", + "requires": { + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "idb": "7.0.1", + "tslib": "^2.1.0" + } + }, + "@firebase/app-check": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.5.15.tgz", + "integrity": "sha512-ifQalGXkXMwGR3F8Glmo1XtDg0UjkwCmI/ff05mxnKGMfs5ZDyw8DikQfna//a/KdYuOBqxlBwS2BhHiobqUUg==", + "requires": { + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "@firebase/app-check-compat": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.2.15.tgz", + "integrity": "sha512-EgD1WEFwwq7aP7DxPSYuUpMt8eAhClA57976D3BaHDbH/IXEuw0DfaeT0LtBb+xJD7J8uxy+YKpudCC8gzUu8g==", + "requires": { + "@firebase/app-check": "0.5.15", + "@firebase/app-check-types": "0.4.0", + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "@firebase/app-check-interop-types": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.1.0.tgz", + "integrity": "sha512-uZfn9s4uuRsaX5Lwx+gFP3B6YsyOKUE+Rqa6z9ojT4VSRAsZFko9FRn6OxQUA1z5t5d08fY4pf+/+Dkd5wbdbA==" + }, + "@firebase/app-check-types": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.4.0.tgz", + "integrity": "sha512-SsWafqMABIOu7zLgWbmwvHGOeQQVQlwm42kwwubsmfLmL4Sf5uGpBfDhQ0CAkpi7bkJ/NwNFKafNDL9prRNP0Q==" + }, + "@firebase/app-compat": { + "version": "0.1.37", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.1.37.tgz", + "integrity": "sha512-doTKYGlVc8ZiQNOl66rpkU/YItRyOxCgMp4YWThXkPM4T/pTi4a9IMCe8K88gVNeYWd8sKW4vSnxjcOG5hQXEA==", + "requires": { + "@firebase/app": "0.8.2", + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "@firebase/app-types": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.8.0.tgz", + "integrity": "sha512-Lec3VVquUwXPn2UReGSsfTxuMBVRmzGIwA/CJnF0LQuPgv9kOmXk9mVqsDMfHxHtqjai0n6wWHR2TqjdVV/bYA==" + }, + "@firebase/auth": { + "version": "0.20.10", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-0.20.10.tgz", + "integrity": "sha512-uAZypmVv/4nijaPVtR/ipjKBmSDPLQ7sNScLHs2DVhdvCklgUUF5+zsEdPlMfKDIfmVQHFwHbUgeKyXDYSRMwQ==", + "requires": { + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "node-fetch": "2.6.7", + "selenium-webdriver": "4.1.2", + "tslib": "^2.1.0" + } + }, + "@firebase/auth-compat": { + "version": "0.2.23", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.2.23.tgz", + "integrity": "sha512-r9YEXaL7YKoFOWHRvVoQ6d5klP+hkSsAtt21UIvP3/BxDDU+yLXN5vVvFHr38apuUeMGN34M7zkY6SihnLutIQ==", + "requires": { + "@firebase/auth": "0.20.10", + "@firebase/auth-types": "0.11.0", + "@firebase/component": "0.5.20", + "@firebase/util": "1.7.2", + "node-fetch": "2.6.7", + "selenium-webdriver": "4.1.2", + "tslib": "^2.1.0" + } + }, + "@firebase/auth-interop-types": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.1.6.tgz", + "integrity": "sha512-etIi92fW3CctsmR9e3sYM3Uqnoq861M0Id9mdOPF6PWIg38BXL5k4upCNBggGUpLIS0H1grMOvy/wn1xymwe2g==", + "requires": {} + }, + "@firebase/auth-types": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.11.0.tgz", + "integrity": "sha512-q7Bt6cx+ySj9elQHTsKulwk3+qDezhzRBFC9zlQ1BjgMueUOnGMcvqmU0zuKlQ4RhLSH7MNAdBV2znVaoN3Vxw==", + "requires": {} + }, + "@firebase/component": { + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.20.tgz", + "integrity": "sha512-wP51tQBlPFprfAWxWjzC/56hG4APhl43jFsgwuqCl3bhVbiKcr278QbrbGNmIXDeGKo4sGZLAnH9whl2apeCmA==", + "requires": { + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "@firebase/database": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.13.9.tgz", + "integrity": "sha512-raQEBgQQybaEoMloJL8wWHQywGQ9mF2VbitvHydsbSNn+KL/xRDjXeQZPuuSbRjkYV6mR8jvQB7gpnzQQNE8Qg==", + "requires": { + "@firebase/auth-interop-types": "0.1.6", + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + } + }, + "@firebase/database-compat": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.2.9.tgz", + "integrity": "sha512-zzyFM3+jW/qYtHojiQirHXGXYyElbqVngEEn/i2gXoSzcK0Y2AL5oHAqGYXLaaW0+t4Zwnssh3HnQJM8C1D0fw==", + "requires": { + "@firebase/component": "0.5.20", + "@firebase/database": "0.13.9", + "@firebase/database-types": "0.9.16", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "@firebase/database-types": { + "version": "0.9.16", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.9.16.tgz", + "integrity": "sha512-dK/uFgHisrVijSoHf9RLJ7NwvlOul2rO/z9ufOSbGd8/TqFVASXz+19mynhDIoSEnyQtJC/NTyBzSPfjz0w61w==", + "requires": { + "@firebase/app-types": "0.8.0", + "@firebase/util": "1.7.2" + } + }, + "@firebase/firestore": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-3.7.1.tgz", + "integrity": "sha512-sDZ79cUf4cwCyRzN74zODgaeUvyt0lGA8YwaasVVqojgznwMG/bIz+/Tny4ZEnLZFrlniCqt2tStWsiC6s3u7g==", + "requires": { + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "@firebase/webchannel-wrapper": "0.8.0", + "@grpc/grpc-js": "^1.3.2", + "@grpc/proto-loader": "^0.6.13", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + } + }, + "@firebase/firestore-compat": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.2.1.tgz", + "integrity": "sha512-XiiTpmUfyZ6QU3Dw9BCT4T+KPvqzada1GsUNX49HmriWHpIn3jTAjsagkigRAnmNDlxS3ki6Yzg9Cs60tpD0tw==", + "requires": { + "@firebase/component": "0.5.20", + "@firebase/firestore": "3.7.1", + "@firebase/firestore-types": "2.5.0", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "@firebase/firestore-types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-2.5.0.tgz", + "integrity": "sha512-I6c2m1zUhZ5SH0cWPmINabDyH5w0PPFHk2UHsjBpKdZllzJZ2TwTkXbDtpHUZNmnc/zAa0WNMNMvcvbb/xJLKA==", + "requires": {} + }, + "@firebase/functions": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.8.7.tgz", + "integrity": "sha512-JHSKdAOzlFJ9NdKoOaq4x6S1q6B3GmYZDg13KIDsE6BC0E9o/eWxOWOjSFJRCP/lpfFwa0rYBRayfUvZxW3BLw==", + "requires": { + "@firebase/app-check-interop-types": "0.1.0", + "@firebase/auth-interop-types": "0.1.6", + "@firebase/component": "0.5.20", + "@firebase/messaging-interop-types": "0.1.0", + "@firebase/util": "1.7.2", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + } + }, + "@firebase/functions-compat": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.2.7.tgz", + "integrity": "sha512-bcUst8ZDJHeVy2Wox4KEM5EizsrrqLzbwFIwJD7KkuSYP8XrlV2gaqJnCvIXXc0Nc4JRGvbXcvFFMXDjhsEp4Q==", + "requires": { + "@firebase/component": "0.5.20", + "@firebase/functions": "0.8.7", + "@firebase/functions-types": "0.5.0", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "@firebase/functions-types": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.5.0.tgz", + "integrity": "sha512-qza0M5EwX+Ocrl1cYI14zoipUX4gI/Shwqv0C1nB864INAD42Dgv4v94BCyxGHBg2kzlWy8PNafdP7zPO8aJQA==" + }, + "@firebase/installations": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.5.15.tgz", + "integrity": "sha512-RVm2nc2d+bEDFzFzQDTTU1Z13fjAD0v88yDLjtRZuT2R7JwvAegQ4F7CupBvnnf7nftkd3kBwdOi8MhMthb3jQ==", + "requires": { + "@firebase/component": "0.5.20", + "@firebase/util": "1.7.2", + "idb": "7.0.1", + "tslib": "^2.1.0" + } + }, + "@firebase/installations-compat": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.1.15.tgz", + "integrity": "sha512-m0atyudsVj6ekmM+djhhzzInMC3Y233YJky9vXUVt5MHQY0mHhqDds9+UIrCa6cpbl+ntI2fOuoYV7y01s3sfw==", + "requires": { + "@firebase/component": "0.5.20", + "@firebase/installations": "0.5.15", + "@firebase/installations-types": "0.4.0", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "@firebase/installations-types": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.4.0.tgz", + "integrity": "sha512-nXxWKQDvBGctuvsizbUEJKfxXU9WAaDhon+j0jpjIfOJkvkj3YHqlLB/HeYjpUn85Pb22BjplpTnDn4Gm9pc3A==", + "requires": {} + }, + "@firebase/logger": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.3.3.tgz", + "integrity": "sha512-POTJl07jOKTOevLXrTvJD/VZ0M6PnJXflbAh5J9VGkmtXPXNG6MdZ9fmRgqYhXKTaDId6AQenQ262uwgpdtO0Q==", "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" + "tslib": "^2.1.0" } }, - "@ctrl/tinycolor": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz", - "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==" + "@firebase/messaging": { + "version": "0.9.19", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.9.19.tgz", + "integrity": "sha512-xu99y/7/P+y3txGtgjsVJZyvx7T5/KdvFgDWS7oZwhKYG0o+DXFvvw3SBMK82LFGFOoyHlJUPqv45EyCPnOPCA==", + "requires": { + "@firebase/component": "0.5.20", + "@firebase/installations": "0.5.15", + "@firebase/messaging-interop-types": "0.1.0", + "@firebase/util": "1.7.2", + "idb": "7.0.1", + "tslib": "^2.1.0" + } }, - "@emotion/babel-plugin": { - "version": "11.10.2", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.2.tgz", - "integrity": "sha512-xNQ57njWTFVfPAc3cjfuaPdsgLp5QOSuRsj9MA6ndEhH/AzuZM86qIQzt6rq+aGBwj3n5/TkLmU5lhAfdRmogA==", + "@firebase/messaging-compat": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.1.19.tgz", + "integrity": "sha512-h5tx4nxfSILeRquk5mKE8Onu7WtL6b7rfB6GKNJKecvkPs3nnq5Z4cp2Av4JUR2Wtt9UxCTfO0iRbbmtrt2bZQ==", "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/plugin-syntax-jsx": "^7.17.12", - "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/serialize": "^1.1.0", - "babel-plugin-macros": "^3.1.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^4.0.0", - "find-root": "^1.1.0", - "source-map": "^0.5.7", - "stylis": "4.0.13" + "@firebase/component": "0.5.20", + "@firebase/messaging": "0.9.19", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" } }, - "@emotion/cache": { - "version": "11.10.3", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.3.tgz", - "integrity": "sha512-Psmp/7ovAa8appWh3g51goxu/z3iVms7JXOreq136D8Bbn6dYraPnmL6mdM8GThEx9vwSn92Fz+mGSjBzN8UPQ==", + "@firebase/messaging-interop-types": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.1.0.tgz", + "integrity": "sha512-DbvUl/rXAZpQeKBnwz0NYY5OCqr2nFA0Bj28Fmr3NXGqR4PAkfTOHuQlVtLO1Nudo3q0HxAYLa68ZDAcuv2uKQ==" + }, + "@firebase/performance": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.5.15.tgz", + "integrity": "sha512-YnnkUehXXzqQefNE5PlPEsXeJYSeY7cMWEdHYTj6u0/F5ntLSAhVZC8jl3Y0fTU1W8a9USQhml6NaXyWiVGmjQ==", + "requires": { + "@firebase/component": "0.5.20", + "@firebase/installations": "0.5.15", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "@firebase/performance-compat": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.1.15.tgz", + "integrity": "sha512-mryHr5eBEpWxBo8b3KM/53SwwVjMVahwdEnhfx1r+zAvmEPEzXUOGBzAC1l5WQ4DrwtDR87uMZ5soiQ/0jl9QQ==", "requires": { - "@emotion/memoize": "^0.8.0", - "@emotion/sheet": "^1.2.0", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", - "stylis": "4.0.13" + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/performance": "0.5.15", + "@firebase/performance-types": "0.1.0", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" } }, - "@emotion/css": { - "version": "11.10.0", - "resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.10.0.tgz", - "integrity": "sha512-dH9f+kSCucc8ilMg0MUA1AemabcyzYpe5EKX24F528PJjD7HyIY/VBNJHxfUdc8l400h2ncAjR6yEDu+DBj2cg==", + "@firebase/performance-types": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.1.0.tgz", + "integrity": "sha512-6p1HxrH0mpx+622Ql6fcxFxfkYSBpE3LSuwM7iTtYU2nw91Hj6THC8Bc8z4nboIq7WvgsT/kOTYVVZzCSlXl8w==" + }, + "@firebase/remote-config": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.3.14.tgz", + "integrity": "sha512-wEOz3Tasxhr5lCGioe0WNZwDOoQhNZK2qGAm5+AlHAPaAhWIWvqUTkKsk3nFRztyRZzj3r9k5Gc2OSpEcQKP1A==", + "requires": { + "@firebase/component": "0.5.20", + "@firebase/installations": "0.5.15", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" + } + }, + "@firebase/remote-config-compat": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.1.15.tgz", + "integrity": "sha512-jGUrZXIxQRMeSrqEaCi3MtMF33NN12TNTQDZlbex2+T2+yTMI/sn3Mq52T/OccCo86DK17WVlXSWQCH1zCD13g==", "requires": { - "@emotion/babel-plugin": "^11.10.0", - "@emotion/cache": "^11.10.0", - "@emotion/serialize": "^1.1.0", - "@emotion/sheet": "^1.2.0", - "@emotion/utils": "^1.2.0" + "@firebase/component": "0.5.20", + "@firebase/logger": "0.3.3", + "@firebase/remote-config": "0.3.14", + "@firebase/remote-config-types": "0.2.0", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" } }, - "@emotion/hash": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", - "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + "@firebase/remote-config-types": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.2.0.tgz", + "integrity": "sha512-hqK5sCPeZvcHQ1D6VjJZdW6EexLTXNMJfPdTwbD8NrXUw6UjWC4KWhLK/TSlL0QPsQtcKRkaaoP+9QCgKfMFPw==" }, - "@emotion/memoize": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + "@firebase/storage": { + "version": "0.9.12", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.9.12.tgz", + "integrity": "sha512-XIAmje0ufvRrxrUU/9tvGCuUIy7WSJf3XM8Y8OV9EW2Dg1w4f8IpraLiUdlirdtFM0UAnO2kDQHoiVQYhRrADQ==", + "requires": { + "@firebase/component": "0.5.20", + "@firebase/util": "1.7.2", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + } }, - "@emotion/serialize": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.0.tgz", - "integrity": "sha512-F1ZZZW51T/fx+wKbVlwsfchr5q97iW8brAnXmsskz4d0hVB4O3M/SiA3SaeH06x02lSNzkkQv+n3AX3kCXKSFA==", + "@firebase/storage-compat": { + "version": "0.1.20", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.1.20.tgz", + "integrity": "sha512-8vruwltKdvEPhYbPXA/otb5fAD7MGsBHpCzktJWvF7eIALa4sUlYt+jJxG5Nwk2FoT1NrwLQ7TtI7zvm6/NinA==", "requires": { - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/unitless": "^0.8.0", - "@emotion/utils": "^1.2.0", - "csstype": "^3.0.2" + "@firebase/component": "0.5.20", + "@firebase/storage": "0.9.12", + "@firebase/storage-types": "0.6.0", + "@firebase/util": "1.7.2", + "tslib": "^2.1.0" } }, - "@emotion/sheet": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.0.tgz", - "integrity": "sha512-OiTkRgpxescko+M51tZsMq7Puu/KP55wMT8BgpcXVG2hqXc0Vo0mfymJ/Uj24Hp0i083ji/o0aLddh08UEjq8w==" + "@firebase/storage-types": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.6.0.tgz", + "integrity": "sha512-1LpWhcCb1ftpkP/akhzjzeFxgVefs6eMD2QeKiJJUGH1qOiows2w5o0sKCUSQrvrRQS1lz3SFGvNR1Ck/gqxeA==", + "requires": {} }, - "@emotion/unitless": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", - "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + "@firebase/util": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.7.2.tgz", + "integrity": "sha512-P3aTihYEMoz2QQlcn0T7av7HLEK9gsTc1ZiN9VA8wnUtEJscUNemCmTmP3RRysqEb3Z+tVVoycztY8f6R36rRw==", + "requires": { + "tslib": "^2.1.0" + } }, - "@emotion/utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", - "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + "@firebase/webchannel-wrapper": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.8.0.tgz", + "integrity": "sha512-Q8erQds5LuAUgNuFOt/tu/abffYUHYxN+Ogp2V5EOssfFG7Ja4ce324Sqyq41u/vB5CSr+tfYS3JzTDrDxCvdw==" }, - "@emotion/weak-memoize": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", - "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + "@grpc/grpc-js": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.7.2.tgz", + "integrity": "sha512-MqqbVynbe3VUSnApFW/dpkDaa9T1ASqRnMWeSPGFO/Ro98R7XUDLacfeBa7RaSI1iFu9GYk5gBKARf0zipFe4w==", + "requires": { + "@grpc/proto-loader": "^0.7.0", + "@types/node": ">=12.12.47" + }, + "dependencies": { + "@grpc/proto-loader": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.3.tgz", + "integrity": "sha512-5dAvoZwna2Py3Ef96Ux9jIkp3iZ62TUsV00p3wVBPNX5K178UbNi8Q7gQVqwXT1Yq9RejIGG9G2IPEo93T6RcA==", + "requires": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^7.0.0", + "yargs": "^16.2.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "protobufjs": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz", + "integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "dependencies": { + "long": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.0.tgz", + "integrity": "sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w==" + } + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + } + } }, - "@eslint/eslintrc": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", - "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", - "dev": true, + "@grpc/proto-loader": { + "version": "0.6.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.13.tgz", + "integrity": "sha512-FjxPYDRTn6Ec3V0arm1FtSpmP6V50wuph2yILpyvTKzjc76oDdoihXqM1DzOW5ubvCC8GivfCnNtfaRE8myJ7g==", "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.11.3", + "yargs": "^16.2.0" + }, + "dependencies": { + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + } } }, "@humanwhocodes/config-array": { @@ -6719,6 +8204,60 @@ "fastq": "^1.6.0" } }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, "@rushstack/eslint-patch": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", @@ -6749,6 +8288,11 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, "@types/node": { "version": "16.11.65", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.65.tgz", @@ -7030,8 +8574,7 @@ "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "base64-js": { "version": "1.5.1", @@ -7047,7 +8590,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -7170,8 +8712,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "concurrently": { "version": "7.4.0", @@ -7236,6 +8777,11 @@ "integrity": "sha512-T/7qvgv70MEvRkZ8p6BasLZmOVYKzOaWNBEHAU8FmveCJkl4nko2quqPQOmy6AJIp5MBanhz9no3A94NoRb0XA==", "dev": true }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "cosmiconfig": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", @@ -7812,6 +9358,14 @@ "reusify": "^1.0.4" } }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -7845,6 +9399,39 @@ "path-exists": "^4.0.0" } }, + "firebase": { + "version": "9.12.1", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-9.12.1.tgz", + "integrity": "sha512-sBp4rvkCC7TUnGeneRNs6GVcajO+iSXmYjxqXN4FsrBzldJ5/AOnDXf4bi9OUZtQSl+EHDgUWShBieht15ijgQ==", + "requires": { + "@firebase/analytics": "0.8.3", + "@firebase/analytics-compat": "0.1.16", + "@firebase/app": "0.8.2", + "@firebase/app-check": "0.5.15", + "@firebase/app-check-compat": "0.2.15", + "@firebase/app-compat": "0.1.37", + "@firebase/app-types": "0.8.0", + "@firebase/auth": "0.20.10", + "@firebase/auth-compat": "0.2.23", + "@firebase/database": "0.13.9", + "@firebase/database-compat": "0.2.9", + "@firebase/firestore": "3.7.1", + "@firebase/firestore-compat": "0.2.1", + "@firebase/functions": "0.8.7", + "@firebase/functions-compat": "0.2.7", + "@firebase/installations": "0.5.15", + "@firebase/installations-compat": "0.1.15", + "@firebase/messaging": "0.9.19", + "@firebase/messaging-compat": "0.1.19", + "@firebase/performance": "0.5.15", + "@firebase/performance-compat": "0.1.15", + "@firebase/remote-config": "0.3.14", + "@firebase/remote-config-compat": "0.1.15", + "@firebase/storage": "0.9.12", + "@firebase/storage-compat": "0.1.20", + "@firebase/util": "1.7.2" + } + }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -7911,8 +9498,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "function-bind": { "version": "1.1.1", @@ -7969,7 +9555,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -8065,6 +9650,11 @@ "react-is": "^16.7.0" } }, + "http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, "http-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", @@ -8084,6 +9674,11 @@ "debug": "4" } }, + "idb": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz", + "integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==" + }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -8095,6 +9690,11 @@ "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -8114,7 +9714,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -8300,6 +9899,11 @@ "is-docker": "^2.0.0" } }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -8424,6 +10028,17 @@ "object.assign": "^4.1.3" } }, + "jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, "jwa": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", @@ -8468,6 +10083,14 @@ "type-check": "~0.4.0" } }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "requires": { + "immediate": "~3.0.5" + } + }, "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -8493,6 +10116,11 @@ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "peer": true }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, "lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -8534,6 +10162,11 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -8589,7 +10222,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -8647,6 +10279,14 @@ "use-sync-external-store": "1.2.0" } }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, "node-releases": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", @@ -8726,7 +10366,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "requires": { "wrappy": "1" } @@ -8773,6 +10412,11 @@ "p-limit": "^3.0.2" } }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -8801,8 +10445,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-key": { "version": "3.1.1", @@ -8847,6 +10490,11 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -8857,6 +10505,26 @@ "react-is": "^16.13.1" } }, + "protobufjs": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + } + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -9306,6 +10974,12 @@ "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==", "peer": true }, + "react-firebase-hooks": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/react-firebase-hooks/-/react-firebase-hooks-5.0.3.tgz", + "integrity": "sha512-0+V2XwInZJNjW8B2cm+U21Hlv4xnp/1tJqIoDg2rjyWzKTQ9VoLPQ9PAt+fMqPumjLz5uCIREY7YqGSSjc439Q==", + "requires": {} + }, "react-icons": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.4.0.tgz", @@ -9333,6 +11007,20 @@ "@emotion/css": "^11.7.1" } }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "regenerator-runtime": { "version": "0.13.9", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", @@ -9389,7 +11077,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "requires": { "glob": "^7.1.3" } @@ -9442,11 +11129,26 @@ "compute-scroll-into-view": "^1.0.17" } }, + "selenium-webdriver": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.1.2.tgz", + "integrity": "sha512-e4Ap8vQvhipgBB8Ry9zBiKGkU6kHKyNnWiavGGLKkrdW81Zv7NVMtFOL/j3yX0G8QScM7XIXijKssNd4EUxSOw==", + "requires": { + "jszip": "^3.6.0", + "tmp": "^0.2.1", + "ws": ">=7.4.6" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, "shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", @@ -9508,6 +11210,14 @@ "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==" }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, "string-convert": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", @@ -9627,6 +11337,14 @@ "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", "peer": true }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "requires": { + "rimraf": "^3.0.0" + } + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -9646,6 +11364,11 @@ "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -9756,11 +11479,45 @@ "which-typed-array": "^1.1.2" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "uuid": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -9814,8 +11571,13 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "ws": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", + "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", + "requires": {} }, "y18n": { "version": "5.0.8", diff --git a/front-end/web-next/package.json b/front-end/web-next/package.json index 7f107908..e7fecc97 100644 --- a/front-end/web-next/package.json +++ b/front-end/web-next/package.json @@ -22,12 +22,14 @@ "cookies-next": "^2.1.1", "crypto-js": "^4.1.1", "cryptojs": "^2.5.3", + "firebase": "^9.12.1", "formik-antd": "^2.0.4", "jose": "^4.10.0", "next": "^12.3.1", "react": "18.2.0", "react-dom": "18.2.0", "react-draggable": "^4.4.5", + "react-firebase-hooks": "^5.0.3", "react-icons": "^4.4.0", "react-infinite-scroll-component": "^6.1.0", "react-organizational-chart": "^2.2.0", diff --git a/front-end/web-next/pages/messages.js b/front-end/web-next/pages/messages.js index ca80663b..1d5ae553 100644 --- a/front-end/web-next/pages/messages.js +++ b/front-end/web-next/pages/messages.js @@ -1,11 +1,76 @@ import Head from 'next/head' +import styles from '../styles/chat.module.css' + import Link from "next/link" import MenuBar from '../componenets/menubar' import MenuLayout from '../componenets/MenuLayout' +import { Descriptions, Tabs, Avatar, List, PageHeader, Button, Input, Space, Image } from 'antd'; +import { db } from '../firebaseauth' +import { useCollection } from "react-firebase-hooks/firestore" +import { collection } from "@firebase/firestore" +import { useEffect, useState } from 'react' + +function Menuelement(props) { + const [snapshot, loading, error] = useCollection(collection(db, "chats")) + const chats = snapshot?.docs.map(doc => ({ id: doc.id, ...doc.data() })) + + + if (loading) return
Loading...
+ + return ( + chats.map(thechat => +
+
+ +
+
+
+

{thechat.name}

+

{new Date(thechat.rectime.seconds * 1000).toLocaleString([], {hourCycle: 'h23',year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit"})}

+
+

+ {thechat.users} +

+
+
+ ) + ) + return <> +
+
+ +
+
+
+

{props.name}

+

2/2/2022

+
+
+ message message message message message message message... +
+ +
+ +
+ +} const Messages = () => { return <> -

OrgChart

+ + 메세지 + + +
+
+ +
+
+ } -export default Messages; \ No newline at end of file +export default Messages; \ No newline at end of file diff --git a/front-end/web-next/styles/chat.module.css b/front-end/web-next/styles/chat.module.css new file mode 100644 index 00000000..0934fd31 --- /dev/null +++ b/front-end/web-next/styles/chat.module.css @@ -0,0 +1,41 @@ +.flexcontainer { + display: flex; +} + +.menuelem { + display: flex; + height: 100px; + border-bottom: 0.5px lightgrey solid; +} +.menuelemtitle { + font-size: 20px; + color: #008272; +} +.imagecontainer { + width: 100px; + height: 100px; + display: flex; + align-items: center; + justify-content: center; + +} +.firstrow { + display: flex; + justify-content: space-between; + width: 250px; + margin-top: 5px; +} +.date { + margin-top: 5px; + font-size: 12px; +} +.content { + width: 250px; + max-width: 250px; + word-wrap: break-word; +} +.sidebar { + width: 360px; + background-color: #F0F0F0; + height: 100vh; +} \ No newline at end of file diff --git a/front-end/web-next/styles/globals.css b/front-end/web-next/styles/globals.css index d295e6ab..24dbdd6d 100644 --- a/front-end/web-next/styles/globals.css +++ b/front-end/web-next/styles/globals.css @@ -15,6 +15,14 @@ body { padding: 0; } +.wordwrap { + white-space: pre-wrap; /* Webkit */ + white-space: -moz-pre-wrap; /* Firefox */ + white-space: -pre-wrap; /* Opera <7 */ + white-space: -o-pre-wrap; /* Opera 7 */ + word-wrap: break-word; /* IE */ +} + a { color: inherit; text-decoration: none; From 031af39610e4e9efc8d6592424b47a30c6bb3cf0 Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Fri, 21 Oct 2022 15:03:47 +0000 Subject: [PATCH 30/48] [Feat]: #110 componentalized chat sidebar --- front-end/web-next/componenets/Chatsidebar.js | 69 +++++++++++++++++ front-end/web-next/pages/home.js | 11 ++- front-end/web-next/pages/messages.js | 77 ++----------------- front-end/web-next/pages/messages/[id].js | 12 +++ front-end/web-next/pages/settings.js | 8 +- 5 files changed, 95 insertions(+), 82 deletions(-) create mode 100644 front-end/web-next/componenets/Chatsidebar.js create mode 100644 front-end/web-next/pages/messages/[id].js diff --git a/front-end/web-next/componenets/Chatsidebar.js b/front-end/web-next/componenets/Chatsidebar.js new file mode 100644 index 00000000..a6e3fa17 --- /dev/null +++ b/front-end/web-next/componenets/Chatsidebar.js @@ -0,0 +1,69 @@ +import Head from 'next/head' +import styles from '../styles/chat.module.css' +import { PageHeader, Image } from 'antd'; +import { db } from '../firebaseauth' +import { useCollection } from "react-firebase-hooks/firestore" +import { collection } from "@firebase/firestore" +import { decodeJwt, jwtVerify } from 'jose'; +import { useEffect, useState } from 'react' +import { getCookie } from 'cookies-next'; +import { redirect } from 'next/dist/server/api-utils' +import { useRouter } from 'next/router' + +function getid() { + const JWTtoken = getCookie('usercookie'); + const { id } = decodeJwt(JWTtoken) + return id +} + +function Menuelement(props) { + const [snapshot, loading, error] = useCollection(collection(db, "chats")) + + if (loading || !snapshot) return
Loading...
+ + const id = getid() + const chats = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })).filter(chat => chat.users.includes(id)) + const router = useRouter() + const redirect = (id) => { + router.push(`/messages/${id}`) + + } + return ( + chats.map(thechat => +
redirect(thechat.id)}> +
+ +
+
+
+

{thechat.name}

+

{new Date(thechat.rectime.seconds * 1000).toLocaleString([], { hourCycle: 'h23', year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit" })}

+
+

+ {thechat.users} +

+
+
+ ) + ) +} +const Sidebar = () => { + return <> + + 메세지 + + +
+
+ +
+
+ + +} + +export default Sidebar; \ No newline at end of file diff --git a/front-end/web-next/pages/home.js b/front-end/web-next/pages/home.js index bd3bb002..d44da938 100644 --- a/front-end/web-next/pages/home.js +++ b/front-end/web-next/pages/home.js @@ -4,7 +4,8 @@ import Image from 'next/image' import unitlogo from '../img/unitlogo.png' import { Descriptions, Tabs, Avatar, List, PageHeader, Button, Input, Space } from 'antd'; import {decryptuser, encryptuser} from '../encryption/userencryption' -import { jwtVerify } from 'jose'; +import { decodeJwt, jwtVerify } from 'jose'; +import { getCookie } from 'cookies-next'; const { Search } = Input; @@ -114,11 +115,9 @@ export async function getServerSideProps(context) { // let decrypt = await decryptuser('test133', ciphertext) // console.log(decrypt) const backendroot = process.env.NEXT_PUBLIC_BACKEND_ROOT - const endpoint = backendroot + 'api/user?search=' - const secret = process.env.JWT_SECRET - const JWTtoken = context.req.cookies['usercookie']; // => 'value' - const { payload } = await jwtVerify(JWTtoken, new TextEncoder().encode(secret)) - let id = payload['id'] + const endpoint = backendroot + 'api/user/id?search=' + const JWTtoken = context.req.cookies['usercookie']; + const { id } = decodeJwt(JWTtoken) const options = { // The method is POST because we are sending data. method: 'GET', diff --git a/front-end/web-next/pages/messages.js b/front-end/web-next/pages/messages.js index 1d5ae553..b6511385 100644 --- a/front-end/web-next/pages/messages.js +++ b/front-end/web-next/pages/messages.js @@ -1,76 +1,11 @@ +import Sidebar from '../componenets/Chatsidebar' import Head from 'next/head' -import styles from '../styles/chat.module.css' +import { PageHeader, Image } from 'antd'; -import Link from "next/link" -import MenuBar from '../componenets/menubar' -import MenuLayout from '../componenets/MenuLayout' -import { Descriptions, Tabs, Avatar, List, PageHeader, Button, Input, Space, Image } from 'antd'; -import { db } from '../firebaseauth' -import { useCollection } from "react-firebase-hooks/firestore" -import { collection } from "@firebase/firestore" -import { useEffect, useState } from 'react' - -function Menuelement(props) { - const [snapshot, loading, error] = useCollection(collection(db, "chats")) - const chats = snapshot?.docs.map(doc => ({ id: doc.id, ...doc.data() })) - - - if (loading) return
Loading...
- - return ( - chats.map(thechat => -
-
- -
-
-
-

{thechat.name}

-

{new Date(thechat.rectime.seconds * 1000).toLocaleString([], {hourCycle: 'h23',year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit"})}

-
-

- {thechat.users} -

-
-
- ) - ) +function chatpage() { return <> -
-
- -
-
-
-

{props.name}

-

2/2/2022

-
-
- message message message message message message message... -
- -
- -
- -} -const Messages = () => { - return <> - - 메세지 - - -
-
- -
-
- - + + } -export default Messages; \ No newline at end of file +export default chatpage; \ No newline at end of file diff --git a/front-end/web-next/pages/messages/[id].js b/front-end/web-next/pages/messages/[id].js new file mode 100644 index 00000000..5a9b0b40 --- /dev/null +++ b/front-end/web-next/pages/messages/[id].js @@ -0,0 +1,12 @@ +import Sidebar from '../../componenets/Chatsidebar' +import Head from 'next/head' +import styles from '../../styles/chat.module.css' +import { PageHeader, Image } from 'antd'; + +function chatpage() { + return <> + + +} + +export default chatpage; \ No newline at end of file diff --git a/front-end/web-next/pages/settings.js b/front-end/web-next/pages/settings.js index a99839e3..c9aee67b 100644 --- a/front-end/web-next/pages/settings.js +++ b/front-end/web-next/pages/settings.js @@ -2,7 +2,7 @@ import Head from 'next/head' import { Button, Input, Upload, Image, TreeSelect, Form, PageHeader, Breadcrumb } from 'antd'; import styles from '../styles/usersettings.module.css' import React, { useEffect, useState } from 'react'; -import { jwtVerify } from 'jose'; +import { decodeJwt, jwtVerify } from 'jose'; import { getCookie } from 'cookies-next'; const backendroot = process.env.NEXT_PUBLIC_BACKEND_ROOT @@ -238,11 +238,9 @@ const Settings = (props) => { export async function getServerSideProps(context) { - let endpoint = backendroot + 'api/user?search=' - const secret = process.env.JWT_SECRET + let endpoint = backendroot + 'api/user/id?search=' const JWTtoken = context.req.cookies['usercookie']; // => 'value' - const { payload } = await jwtVerify(JWTtoken, new TextEncoder().encode(secret)) - let id = payload['id'] + const { id } = decodeJwt(JWTtoken) const options = { // The method is POST because we are sending data. method: 'GET', From 97c08826424538db5648e19472dc6c32fa5662c9 Mon Sep 17 00:00:00 2001 From: Yunseong Choe <68419358+marunemo@users.noreply.github.com> Date: Fri, 21 Oct 2022 15:07:40 +0000 Subject: [PATCH 31/48] [Feat]Create organizational chart api MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 조직도 api 생성 및 연결 작업 시작 #93 --- back-end/controllers/chartController.js | 240 ++++++++++++++++++ back-end/models/chartModel.js | 41 +++ back-end/routes/chartRoutes.js | 20 ++ back-end/server.js | 2 + .../web-next/componenets/OrganizationForm.js | 18 +- front-end/web-next/componenets/Organogram.js | 87 +++++-- 6 files changed, 379 insertions(+), 29 deletions(-) create mode 100644 back-end/controllers/chartController.js create mode 100644 back-end/models/chartModel.js create mode 100644 back-end/routes/chartRoutes.js diff --git a/back-end/controllers/chartController.js b/back-end/controllers/chartController.js new file mode 100644 index 00000000..effc1abc --- /dev/null +++ b/back-end/controllers/chartController.js @@ -0,0 +1,240 @@ +const asyncHandler = require("express-async-handler"); +const Chart = require("../models/chartModel"); +const User = require("../models/userModel.js"); +const jwt = require("jsonwebtoken"); + +//@description Get organizational chart as array list +//@route GET /api/chart +//@access Protected +const getChart = asyncHandler(async (req, res) => { + const auth = req.headers.authorization; + + if (!auth || !auth.startsWith('Bearer')) { + res.status(401); + throw new Error('토큰이 없거나 인증되지 않았습니다.'); + } + + try { + const token = auth.split(' ')[1]; + + const decoded = jwt.verify(token, process.env.JWT_SECRET); + const currentUser = await User.findById(decoded.id).select("-password"); + const currentUnit = await currentUser.Unit?.Unitname; + + if (!currentUnit) + throw new ReferenceError('사용자의 부대가 설정되지 않았습니다.'); + + const unitOrganization = await Chart.find({ Unit: { $eq: currentUnit } }); + res.send(unitOrganization); + } + catch (error) { + if(error === ReferenceError) { + res.status(400); + throw new Error(error); + } + + res.status(401); + throw new Error('잘못된 토큰입니다.'); + } +}); + +//@description Add organizational chart +//@route POST /api/chart/add +//@access Protected +const addChart = asyncHandler(async (req, res) => { + const { + Name, + Rank, + Position, + DoDID, + Number, + MilNumber, + Email, + Parent + } = req.body; + const auth = req.headers.authorization; + + if (!auth || !auth.startsWith('Bearer')) { + res.status(401); + throw new Error('토큰이 없거나 인증되지 않았습니다.'); + } + + if (!Name || !Rank) { + res.status(400); + throw new Error("모든 정보를 입력하세요."); + } + + try { + const token = auth.split(' ')[1]; + + const decoded = jwt.verify(token, process.env.JWT_SECRET); + const currentUser = await User.findById(decoded.id).select("-password"); + const currentUnit = await currentUser.Unit?.Unitname; + + if (!currentUnit) { + res.status(400); + throw new Error('사용자의 부대가 설정되지 않았습니다.'); + } + + const newChart = Chart.create({ + Name, + Rank, + Position, + DoDID, + Number, + MilNumber, + Email, + Parent, + Unit: currentUnit + }); + + if (newChart) { + res.status(201).json({ + Name, + Rank, + Position, + DoDID, + Number, + MilNumber, + Email, + Parent, + Unit: currentUnit + }) + } + else { + res.send(400); + throw new Error('조직도를 추가/수정할 수 없습니다.') + } + } + catch (error) { + res.status(401); + throw new Error('잘못된 토큰입니다.'); + } +}); + +//@description Edit organizational chart +//@route POST /api/chart/edit +//@access Protected +const editChart = asyncHandler(async (req, res) => { + const { + _id, + Name, + Rank, + Position, + DoDID, + Number, + MilNumber, + Email, + Parent + } = req.body; + const auth = req.headers.authorization; + + if (!auth || !auth.startsWith('Bearer')) { + res.status(401); + throw new Error('토큰이 없거나 인증되지 않았습니다.'); + } + + if (!_id || !Name || !Rank) { + res.status(400); + throw new Error("모든 정보를 입력하세요."); + } + + try { + const token = auth.split(' ')[1]; + + const decoded = jwt.verify(token, process.env.JWT_SECRET); + const currentUser = await User.findById(decoded.id).select("-password"); + const currentUnit = await currentUser.Unit?.Unitname; + + if (!currentUnit) { + res.status(400); + throw new Error('사용자의 부대가 설정되지 않았습니다.'); + } + + const updatedChart = Chart.updateOne({ _id: _id }, { + Name, + Rank, + Position, + DoDID, + Number, + MilNumber, + Email, + Parent, + Unit: currentUnit + }); + + if (updatedChart) { + res.status(200).json({ + Name, + Rank, + Position, + DoDID, + Number, + MilNumber, + Email, + Parent, + Unit: currentUnit + }) + } + else { + res.send(400); + throw new Error('조직도를 추가/수정할 수 없습니다.') + } + } + catch (error) { + res.status(401); + throw new Error('잘못된 토큰입니다.'); + } +}); + +//@description Delete organizational chart +//@route POST /api/chart/delete +//@access Protected +const deleteChart = asyncHandler(async (req, res) => { + const { _id } = req.body; + const auth = req.headers.authorization; + + if (!auth || !auth.startsWith('Bearer')) { + res.status(401); + throw new Error('토큰이 없거나 인증되지 않았습니다.'); + } + + if (!_id || !Name || !Rank) { + res.status(400); + throw new Error("모든 정보를 입력하세요."); + } + + try { + const token = auth.split(' ')[1]; + + const decoded = jwt.verify(token, process.env.JWT_SECRET); + const currentUser = await User.findById(decoded.id).select("-password"); + const currentUnit = await currentUser.Unit?.Unitname; + + if (!currentUnit) { + res.status(400); + throw new Error('사용자의 부대가 설정되지 않았습니다.'); + } + + const deleteChart = Chart.remove({ _id: _id }); + + if (deleteChart) { + res.status(200); + } + else { + res.send(400); + throw new Error('조직도를 추가/수정할 수 없습니다.') + } + } + catch (error) { + res.status(401); + throw new Error('잘못된 토큰입니다.'); + } +}); + +module.exports = { + getChart, + addChart, + editChart, + deleteChart +}; diff --git a/back-end/models/chartModel.js b/back-end/models/chartModel.js new file mode 100644 index 00000000..3ff26d4e --- /dev/null +++ b/back-end/models/chartModel.js @@ -0,0 +1,41 @@ +const mongoose = require("mongoose"); + +const chartModel = mongoose.Schema({ + Name: { + type: String, + required: true + }, + Rank: { + type: String, + required: true + }, + Unit: { + type: String, + required: true + }, + Position: { + type: String + }, + DoDID: { + type: String + }, + Number: { + type: String + }, + MilNumber: { + type: String + }, + Email: { + type: String + }, + Parent: { + type: String, + default: null + } +}, { + timestamps: true +}); + +const Chart = mongoose.model("Chart", chartModel); + +module.exports = Chart; diff --git a/back-end/routes/chartRoutes.js b/back-end/routes/chartRoutes.js new file mode 100644 index 00000000..372a39b0 --- /dev/null +++ b/back-end/routes/chartRoutes.js @@ -0,0 +1,20 @@ +const express = require("express"); +const { + getChart, + addChart, + editChart, + deleteChart +} = require('../controllers/chartController'); +const { + protect, + onlyAdmin +} = require("../middleware/authMiddleware"); + +const router = express.Router(); + +router.route("/").get(protect, getChart); +router.route("/add").post(onlyAdmin, addChart); +router.route("/edit").post(onlyAdmin, editChart); +router.route("/delete").post(onlyAdmin, deleteChart); + +module.exports = router; diff --git a/back-end/server.js b/back-end/server.js index 4629c026..f34c8c75 100644 --- a/back-end/server.js +++ b/back-end/server.js @@ -8,6 +8,7 @@ const messageRoutes = require("./routes/messageRoutes"); const unitRoutes = require("./routes/unitRoutes"); const reportRoutes = require("./routes/reportRoutes"); const commentRoutes = require("./routes/commentRoutes"); +const chartRoutes = require("./routes/chartRoutes"); const reportsysRoutes = require("./routes/reportsysRoutes"); const { notFound, @@ -33,6 +34,7 @@ app.use("/api/unit", unitRoutes); app.use("/api/report", reportRoutes); app.use("/api/comment", commentRoutes); app.use("/api/reportsys", reportsysRoutes); +app.use("/api/chart", chartRoutes); /*const __dirname1 = path.resolve(); diff --git a/front-end/web-next/componenets/OrganizationForm.js b/front-end/web-next/componenets/OrganizationForm.js index bfc328a7..ee45e6ce 100644 --- a/front-end/web-next/componenets/OrganizationForm.js +++ b/front-end/web-next/componenets/OrganizationForm.js @@ -2,6 +2,15 @@ import { useState, useCallback, useEffect } from 'react'; import { Modal, Image, Row, Col, Select } from 'antd'; import Styles from '../styles/OrganizationForm.module.css'; +function InfoElement(props) { + return ( +
+
{props.label}
+
{props.content}
+
+ ) +} + function InputElement(props) { return (
@@ -89,16 +98,11 @@ function OrganizationForm(props) { - - serializedEdit('unit', event.target.value)} /> - - - serializedEdit('position', event.target.value)} /> - + - serializedEdit('roles', event.target.value)} /> + serializedEdit('position', event.target.value)} /> serializedEdit('email', event.target.value)} /> diff --git a/front-end/web-next/componenets/Organogram.js b/front-end/web-next/componenets/Organogram.js index 43fca12a..53b6aacf 100644 --- a/front-end/web-next/componenets/Organogram.js +++ b/front-end/web-next/componenets/Organogram.js @@ -1,6 +1,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import { Tree, TreeNode } from 'react-organizational-chart'; import { Button, Image, Row, Col } from 'antd'; +import { getCookie } from 'cookies-next'; import OrganizationCard from './OrganizationCard'; import Styles from '../styles/Organogram.module.css'; @@ -83,8 +84,22 @@ function Organogram(props) { const [orgDataTree, setOrgDataTree] = useState([]); useEffect(() => { - setOrgData(props.renderData); - }, [props.renderData]); + fetch(process.env.NEXT_PUBLIC_BACKEND_ROOT + 'api/chart', { + 'method': 'GET', + 'headers': { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${getCookie('usercookie')}` + }, + }) + .then(response => response.json()) + .then(data => { + console.log(data) + // const objectData = data.reduce((preData, node) => { + // preData[node._id] = node; + // }, {}) + // setOrgData(objectData) + }); + }, []); useEffect(() => { makeTree(orgData); @@ -99,31 +114,59 @@ function Organogram(props) { setCardOpened(true); }, [setSelectedOrgInfo, setCardOpened]); - const createNode = useCallback((node) => { - // node key generate - const randomKey = Math.random().toString(36).substring(2, 10); - node['key'] = randomKey; - - setOrgData(treeNode => ({ ...treeNode, [randomKey]: node })); + const createNode = useCallback(async (node) => { + await fetch(process.env.NEXT_PUBLIC_BACKEND_ROOT + 'api/chart/add', { + 'method': 'POST', + 'headers': { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${getCookie('usercookie')}` + }, + 'body': JSON.stringify(node) + }) + .then(response => setOrgData(treeNode => ({ ...treeNode, [response._id]: node }))) }, [setOrgData]); - const updateNode = useCallback((node) => { - setOrgData(treeNode => ({ ...treeNode, [node.key]: node })); + const updateNode = useCallback(async (node) => { + await fetch(process.env.NEXT_PUBLIC_BACKEND_ROOT + 'api/chart/edit', { + 'method': 'POST', + 'headers': { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${getCookie('usercookie')}` + }, + 'body': JSON.stringify(node) + }).then(response => setOrgData(treeNode => ({ ...treeNode, [response._id]: node }))) }, [setOrgData]); - const deleteNode = useCallback((node) => { - setOrgData(treeNode => { - const nodeCopy = { ...treeNode }; - - // Redirection for children of removed node - const nodeChildren = Object.values(nodeCopy).filter((data) => data.parent == node.key); - for (let child of nodeChildren) - child.parent = node.parent; + const deleteNode = useCallback(async (node) => { + const nodeCopy = { ...orgData }; + + // Redirection for children of removed node + const nodeChildren = Object.values(nodeCopy).filter((data) => data.parent == node._id); + for (let child of nodeChildren) { + child.parent = node.parent; + await fetch(process.env.NEXT_PUBLIC_BACKEND_ROOT + 'api/chart/edit', { + 'method': 'POST', + 'headers': { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${getCookie('usercookie')}` + }, + 'body': JSON.stringify(child) + }); + } - delete nodeCopy[node.key] - return nodeCopy; - }); - }, [setOrgData]); + await fetch(process.env.NEXT_PUBLIC_BACKEND_ROOT + 'api/chart/delete', { + 'method': 'POST', + 'headers': { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${getCookie('usercookie')}` + }, + 'body': JSON.stringify(node) + }) + .then(() => { + delete nodeCopy[node._id]; + setOrgData(nodeCopy); + }) + }, [orgData, setOrgData]); const makeTree = useCallback((data) => { // Deep Copy for object From 75116af230d8b28002c252d042a9c351a8f57719 Mon Sep 17 00:00:00 2001 From: Yunseong Choe <68419358+marunemo@users.noreply.github.com> Date: Sat, 22 Oct 2022 02:43:43 +0000 Subject: [PATCH 32/48] [Fix]Activate read chart data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 조직도 데이터를 읽어오지 못하는 오류 수정 조직도 데이터를 읽을 때 조직도에 아무것도 없을 경우, 자기자신의 정보로 새로 생성할 수 있도록 설정 --- back-end/controllers/chartController.js | 204 +++++++----------- back-end/controllers/reportControllers.js | 12 +- front-end/web-next/componenets/MemoForm.js | 3 +- .../web-next/componenets/OrganizationCard.js | 15 +- .../web-next/componenets/OrganizationForm.js | 16 +- front-end/web-next/componenets/Organogram.js | 18 +- 6 files changed, 101 insertions(+), 167 deletions(-) diff --git a/back-end/controllers/chartController.js b/back-end/controllers/chartController.js index effc1abc..902f100d 100644 --- a/back-end/controllers/chartController.js +++ b/back-end/controllers/chartController.js @@ -1,41 +1,28 @@ const asyncHandler = require("express-async-handler"); +const UnitM = require("../models/unitModel"); const Chart = require("../models/chartModel"); -const User = require("../models/userModel.js"); -const jwt = require("jsonwebtoken"); //@description Get organizational chart as array list //@route GET /api/chart //@access Protected const getChart = asyncHandler(async (req, res) => { - const auth = req.headers.authorization; + const currentUser = req.user; + const currentUnit = await UnitM.findOne({ _id: currentUser.Unit }); - if (!auth || !auth.startsWith('Bearer')) { - res.status(401); - throw new Error('토큰이 없거나 인증되지 않았습니다.'); + if (!currentUnit) { + res.status(400); + throw new Error('사용자의 부대가 설정되지 않았습니다.'); } - try { - const token = auth.split(' ')[1]; - - const decoded = jwt.verify(token, process.env.JWT_SECRET); - const currentUser = await User.findById(decoded.id).select("-password"); - const currentUnit = await currentUser.Unit?.Unitname; - - if (!currentUnit) - throw new ReferenceError('사용자의 부대가 설정되지 않았습니다.'); - - const unitOrganization = await Chart.find({ Unit: { $eq: currentUnit } }); - res.send(unitOrganization); - } - catch (error) { - if(error === ReferenceError) { - res.status(400); - throw new Error(error); - } - - res.status(401); - throw new Error('잘못된 토큰입니다.'); + const unitOrganization = await Chart.find({ Unit: { $eq: currentUnit.Unitname } }); + if(unitOrganization.length === 0) { + await Chart.create({ + Name: currentUser.Name, + Rank: currentUser.Rank, + Unit: currentUnit.Unitname + }) } + res.send(unitOrganization); }); //@description Add organizational chart @@ -52,31 +39,34 @@ const addChart = asyncHandler(async (req, res) => { Email, Parent } = req.body; - const auth = req.headers.authorization; - - if (!auth || !auth.startsWith('Bearer')) { - res.status(401); - throw new Error('토큰이 없거나 인증되지 않았습니다.'); - } if (!Name || !Rank) { res.status(400); throw new Error("모든 정보를 입력하세요."); } - try { - const token = auth.split(' ')[1]; + const currentUser = req.user; + const currentUnit = await currentUser.Unit?.Unitname; - const decoded = jwt.verify(token, process.env.JWT_SECRET); - const currentUser = await User.findById(decoded.id).select("-password"); - const currentUnit = await currentUser.Unit?.Unitname; + if (!currentUnit) { + res.status(400); + throw new Error('사용자의 부대가 설정되지 않았습니다.'); + } - if (!currentUnit) { - res.status(400); - throw new Error('사용자의 부대가 설정되지 않았습니다.'); - } + const newChart = await Chart.create({ + Name, + Rank, + Position, + DoDID, + Number, + MilNumber, + Email, + Parent, + Unit: currentUnit + }); - const newChart = Chart.create({ + if (newChart) { + res.status(201).json({ Name, Rank, Position, @@ -86,29 +76,11 @@ const addChart = asyncHandler(async (req, res) => { Email, Parent, Unit: currentUnit - }); - - if (newChart) { - res.status(201).json({ - Name, - Rank, - Position, - DoDID, - Number, - MilNumber, - Email, - Parent, - Unit: currentUnit - }) - } - else { - res.send(400); - throw new Error('조직도를 추가/수정할 수 없습니다.') - } + }) } - catch (error) { - res.status(401); - throw new Error('잘못된 토큰입니다.'); + else { + res.send(400); + throw new Error('조직도를 추가/수정할 수 없습니다.') } }); @@ -127,31 +99,34 @@ const editChart = asyncHandler(async (req, res) => { Email, Parent } = req.body; - const auth = req.headers.authorization; - - if (!auth || !auth.startsWith('Bearer')) { - res.status(401); - throw new Error('토큰이 없거나 인증되지 않았습니다.'); - } if (!_id || !Name || !Rank) { res.status(400); throw new Error("모든 정보를 입력하세요."); } - try { - const token = auth.split(' ')[1]; + const currentUser = req.user; + const currentUnit = await currentUser.Unit?.Unitname; - const decoded = jwt.verify(token, process.env.JWT_SECRET); - const currentUser = await User.findById(decoded.id).select("-password"); - const currentUnit = await currentUser.Unit?.Unitname; + if (!currentUnit) { + res.status(400); + throw new Error('사용자의 부대가 설정되지 않았습니다.'); + } - if (!currentUnit) { - res.status(400); - throw new Error('사용자의 부대가 설정되지 않았습니다.'); - } + const updatedChart = Chart.updateOne({ _id: _id }, { + Name, + Rank, + Position, + DoDID, + Number, + MilNumber, + Email, + Parent, + Unit: currentUnit + }); - const updatedChart = Chart.updateOne({ _id: _id }, { + if (updatedChart) { + res.status(200).json({ Name, Rank, Position, @@ -161,29 +136,11 @@ const editChart = asyncHandler(async (req, res) => { Email, Parent, Unit: currentUnit - }); - - if (updatedChart) { - res.status(200).json({ - Name, - Rank, - Position, - DoDID, - Number, - MilNumber, - Email, - Parent, - Unit: currentUnit - }) - } - else { - res.send(400); - throw new Error('조직도를 추가/수정할 수 없습니다.') - } + }) } - catch (error) { - res.status(401); - throw new Error('잘못된 토큰입니다.'); + else { + res.send(400); + throw new Error('조직도를 추가/수정할 수 없습니다.') } }); @@ -192,43 +149,28 @@ const editChart = asyncHandler(async (req, res) => { //@access Protected const deleteChart = asyncHandler(async (req, res) => { const { _id } = req.body; - const auth = req.headers.authorization; - - if (!auth || !auth.startsWith('Bearer')) { - res.status(401); - throw new Error('토큰이 없거나 인증되지 않았습니다.'); - } if (!_id || !Name || !Rank) { res.status(400); throw new Error("모든 정보를 입력하세요."); } - try { - const token = auth.split(' ')[1]; - - const decoded = jwt.verify(token, process.env.JWT_SECRET); - const currentUser = await User.findById(decoded.id).select("-password"); - const currentUnit = await currentUser.Unit?.Unitname; + const currentUser = req.user; + const currentUnit = await currentUser.Unit?.Unitname; - if (!currentUnit) { - res.status(400); - throw new Error('사용자의 부대가 설정되지 않았습니다.'); - } + if (!currentUnit) { + res.status(400); + throw new Error('사용자의 부대가 설정되지 않았습니다.'); + } - const deleteChart = Chart.remove({ _id: _id }); + const deleteChart = Chart.remove({ _id: _id }); - if (deleteChart) { - res.status(200); - } - else { - res.send(400); - throw new Error('조직도를 추가/수정할 수 없습니다.') - } + if (deleteChart) { + res.status(200); } - catch (error) { - res.status(401); - throw new Error('잘못된 토큰입니다.'); + else { + res.send(400); + throw new Error('조직도를 추가/수정할 수 없습니다.') } }); @@ -237,4 +179,4 @@ module.exports = { addChart, editChart, deleteChart -}; +}; \ No newline at end of file diff --git a/back-end/controllers/reportControllers.js b/back-end/controllers/reportControllers.js index b1786cc3..dc24e2b8 100644 --- a/back-end/controllers/reportControllers.js +++ b/back-end/controllers/reportControllers.js @@ -4,8 +4,6 @@ const Reportsys = require("../models/reportModel"); const UnitM = require("../models/unitModel"); const UserM = require("../models/userModel"); const getScore = require('../ai/classifier.js') -var mongoose = require('mongoose'); -const jwt = require("jsonwebtoken"); //@description Get all report cards //@route GET /api/report @@ -26,7 +24,6 @@ const addReportCard = asyncHandler(async (req, res) => { Invited, Content, Title, - UserToken } = req.body; if (!Type || !ReportingSystem || !Invited || !Content || !Title) { @@ -34,12 +31,9 @@ const addReportCard = asyncHandler(async (req, res) => { throw new Error("모든 정보를 입력하세요."); } - //decodes token id - const decoded = jwt.verify(UserToken, process.env.JWT_SECRET); - const currentUser = await UserM.findById(decoded.id).select("-password"); - - let currentUnit = currentUser.Unit - let Severity = await getScore(Content) + const currentUser = req.user; + let currentUnit = currentUser.Unit; + let Severity = await getScore(Content); const report = await Report.create({ User: currentUser, Type, diff --git a/front-end/web-next/componenets/MemoForm.js b/front-end/web-next/componenets/MemoForm.js index eb37a6db..c68a2ffd 100644 --- a/front-end/web-next/componenets/MemoForm.js +++ b/front-end/web-next/componenets/MemoForm.js @@ -183,8 +183,7 @@ function MemoForm(props) { Type: memoType, ReportingSystem: reportOrgList.map((org) => (org.title)), Invited: addUserList, - Content: memoContent, - UserToken: getCookie('usercookie') + Content: memoContent } await fetch(process.env.NEXT_PUBLIC_BACKEND_ROOT + 'api/report/', { diff --git a/front-end/web-next/componenets/OrganizationCard.js b/front-end/web-next/componenets/OrganizationCard.js index 2ebcc302..329152f3 100644 --- a/front-end/web-next/componenets/OrganizationCard.js +++ b/front-end/web-next/componenets/OrganizationCard.js @@ -66,23 +66,22 @@ function OrganizationCard(props) {
- {props.data.name} - {props.data.rank} + {props.data.Name} + {props.data.Rank}
{props.data.DoDID}
- - + - - + + - - + +
- serializedEdit('name', event.target.value)} /> + serializedEdit('name', event.target.value)} /> serializedEdit('name', event.target.value)} /> + serializedEdit('Name', event.target.value)} /> { setchatTitle(event.target.value) }}> + +

인원 추가

+ +
+ +

{errormsg}

+
+ + +
- + +
+
+ {children}
+
diff --git a/front-end/web-next/componenets/additionalpeople.js b/front-end/web-next/componenets/additionalpeople.js new file mode 100644 index 00000000..9c5e3bef --- /dev/null +++ b/front-end/web-next/componenets/additionalpeople.js @@ -0,0 +1,133 @@ +import { useState, useCallback } from 'react'; +import { Modal, Select, Button, Avatar, Row, Col } from 'antd'; +import { PlusOutlined, ArrowRightOutlined, CloseOutlined } from '@ant-design/icons' +import { getCookie } from 'cookies-next'; +import {Convertrank} from '../helperfunction/convertrank' +import styles from '../styles/MemoForm.module.css'; + +const Addperson = ({ fetchedInvitedList, setFetchedInvitedList, addUser, setAddUser, style }) => { + const [addUserList, setAddUserList] = useState([]); + // const [addUser, setAddUser] = useState([]); + function UserNode(props) { + return ( + + + + + +
{convertrank(props.rank)} {props.name}
+
{props.position}
+ +
+ ) + } + function additionalPerson(user, key, onRemove = null) { + return ( + + + + + +
+ { + addUserList.length !== 0 && + addUserList.map((user, index) => additionalPerson(user, index, () => deleteList(setAddUserList, user.key))) + } +
+ + + +} + + + +export default Addperson; \ No newline at end of file diff --git a/front-end/web-next/helperfunction/convertrank.js b/front-end/web-next/helperfunction/convertrank.js new file mode 100644 index 00000000..c89d591b --- /dev/null +++ b/front-end/web-next/helperfunction/convertrank.js @@ -0,0 +1,25 @@ +export function Convertrank(val) { + const rank = new Map() + + rank["PVT"] = "이병" + rank["PFC"] = "일병" + rank["CPL"] = "상병" + rank["SGT"] = "병장" + rank["SST"] = "하사" + rank["SFC"] = "중사" + rank["MST"] = "상사" + rank["SGM"] = "원사" + rank["SEC"] = "소위" + rank["LIU"] = "중위" + rank["CPT"] = "대위" + rank["MAJ"] = "소령" + rank["LTC"] = "중령" + rank["COL"] = "대령" + rank["BG"] = "준장" + rank["MG"] = "소장" + rank["LG"] = "중장" + rank["GEN"] = "대장" + return rank[val] + + +} \ No newline at end of file diff --git a/front-end/web-next/pages/home.js b/front-end/web-next/pages/home.js index d44da938..71202513 100644 --- a/front-end/web-next/pages/home.js +++ b/front-end/web-next/pages/home.js @@ -1,6 +1,6 @@ import Head from 'next/head' import style from '../styles/homepage.module.css' -import Image from 'next/image' +import {Image} from 'antd' import unitlogo from '../img/unitlogo.png' import { Descriptions, Tabs, Avatar, List, PageHeader, Button, Input, Space } from 'antd'; import {decryptuser, encryptuser} from '../encryption/userencryption' diff --git a/front-end/web-next/pages/messages/[id].js b/front-end/web-next/pages/messages/[id].js index 5a9b0b40..29d76c6e 100644 --- a/front-end/web-next/pages/messages/[id].js +++ b/front-end/web-next/pages/messages/[id].js @@ -5,7 +5,9 @@ import { PageHeader, Image } from 'antd'; function chatpage() { return <> - + +

hi!

+
} diff --git a/front-end/web-next/styles/chat.module.css b/front-end/web-next/styles/chat.module.css index 0934fd31..7b188968 100644 --- a/front-end/web-next/styles/chat.module.css +++ b/front-end/web-next/styles/chat.module.css @@ -11,6 +11,22 @@ font-size: 20px; color: #008272; } + +.button { + background-color: #008272; + color: white; + font-size: 14px; + border: none; + padding: 5px; + height: 35px; +} + +.button:hover { + background-color: #00695d; + color: white; + cursor: pointer; + +} .imagecontainer { width: 100px; height: 100px; @@ -38,4 +54,13 @@ width: 360px; background-color: #F0F0F0; height: 100vh; +} + +.error { + color: red; + font-size: 14px; + margin-left: 8px; + line-height: 35px; + margin-top: 20px; + margin-bottom: 0px; } \ No newline at end of file diff --git a/front-end/web-next/styles/globals.css b/front-end/web-next/styles/globals.css index ab5f115f..c30e8522 100644 --- a/front-end/web-next/styles/globals.css +++ b/front-end/web-next/styles/globals.css @@ -15,6 +15,12 @@ body { padding: 0; } +h3{ + margin: 0; +} +div { + margin: 0; +} .wordwrap { white-space: pre-wrap; /* Webkit */ white-space: -moz-pre-wrap; /* Firefox */ @@ -23,6 +29,11 @@ body { word-wrap: break-word; /* IE */ } +.ant-btn-primary { + display: flex; + justify-content: center; + align-items: center; +} a { color: inherit; text-decoration: none; From 3ccf1bdcf39707bd4ee080650a0dd9253b79b8be Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Sat, 22 Oct 2022 06:21:36 +0000 Subject: [PATCH 40/48] [Feat]: #110 changes to usercontroller to enable search by id --- back-end/controllers/userControllers.js | 15 +++++++++++++++ back-end/routes/userRoutes.js | 2 ++ 2 files changed, 17 insertions(+) diff --git a/back-end/controllers/userControllers.js b/back-end/controllers/userControllers.js index 3b78dd6f..3367859f 100644 --- a/back-end/controllers/userControllers.js +++ b/back-end/controllers/userControllers.js @@ -4,6 +4,20 @@ const generateToken = require("../config/generateToken"); const bcrypt = require("bcryptjs"); const UnitM = require("../models/unitModel"); +const getuserbyid = asyncHandler(async (req, res) => { + const keyword = req.query.search + const index = req.query.index; + if (index) { + res.send(users.slice(parseInt(index) * 4, parseInt(index) * 4 + 4)); + } else if (keyword) { + let user = await User.find({ _id: { $eq: keyword }}, {password: 0}) + res.send(user); //.find({ _id: { $ne: req.user._id } })); + } else { + res.status(400); + throw new Error("잘못된 요청입니다."); + } +}); + //@description Get or Search all users //@route GET /api/user?search=?index= //@access Protected @@ -399,6 +413,7 @@ const updatePic = asyncHandler(async (req, res) => { }); module.exports = { + getuserbyid, allUsers, addUser, registerUser, diff --git a/back-end/routes/userRoutes.js b/back-end/routes/userRoutes.js index 5c9fe179..23baef38 100644 --- a/back-end/routes/userRoutes.js +++ b/back-end/routes/userRoutes.js @@ -1,5 +1,6 @@ const express = require("express"); const { + getuserbyid, registerUser, authUser, allUsers, @@ -16,6 +17,7 @@ const { const router = express.Router(); router.route("/").get(protect, allUsers); //protect, +router.route("/id").get(protect, getuserbyid); //protect, router.route("/").put(protect, updateUser); router.route("/updateweb").post(onlyAdmin, updateUser2); router.route("/pic").put(protect, updatePic); //protect, From d87fcac6b3b6a2a789c9c45f44cd349ac865218f Mon Sep 17 00:00:00 2001 From: Yunseong Choe <68419358+marunemo@users.noreply.github.com> Date: Sat, 22 Oct 2022 08:38:57 +0000 Subject: [PATCH 41/48] [Fix]Prevent null from casting string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit antd의 select에 의해 key 값이 string으로 강제로 casting되는 오류 수정 --- front-end/web-next/componenets/OrganizationForm.js | 2 +- front-end/web-next/componenets/Organogram.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/front-end/web-next/componenets/OrganizationForm.js b/front-end/web-next/componenets/OrganizationForm.js index 8191ea4a..a037c297 100644 --- a/front-end/web-next/componenets/OrganizationForm.js +++ b/front-end/web-next/componenets/OrganizationForm.js @@ -120,7 +120,7 @@ function OrganizationForm(props) { serializedEdit('Parent', key)} + onChange={({ key }) => serializedEdit('Parent', key === 'null' ? null : key)} selfKey={formData._id} nodeList={[{ 'key': null, 'value': '없음' }, ...props.nodeList]} /> diff --git a/front-end/web-next/componenets/Organogram.js b/front-end/web-next/componenets/Organogram.js index 775934db..04691300 100644 --- a/front-end/web-next/componenets/Organogram.js +++ b/front-end/web-next/componenets/Organogram.js @@ -208,7 +208,7 @@ function Organogram(props) { <> {orgDataTree.map((dataNode) => ( - + {renderNode(dataNode, chooseOrgInfo)} ))} From 166a831135420d0bde5409cd602d8ee4afc1b300 Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Sat, 22 Oct 2022 10:33:35 +0000 Subject: [PATCH 42/48] [Feat]: #110 Added message boxes --- front-end/web-next/componenets/Chatsidebar.js | 55 ++++++- front-end/web-next/package-lock.json | 47 ++++++ front-end/web-next/package.json | 2 + front-end/web-next/pages/messages.js | 6 +- front-end/web-next/pages/messages/[id].js | 150 +++++++++++++++++- front-end/web-next/styles/chat.module.css | 1 + front-end/web-next/styles/chatpage.module.css | 44 +++++ front-end/web-next/styles/globals.css | 3 + 8 files changed, 297 insertions(+), 11 deletions(-) create mode 100644 front-end/web-next/styles/chatpage.module.css diff --git a/front-end/web-next/componenets/Chatsidebar.js b/front-end/web-next/componenets/Chatsidebar.js index ded024cf..b83fd72d 100644 --- a/front-end/web-next/componenets/Chatsidebar.js +++ b/front-end/web-next/componenets/Chatsidebar.js @@ -10,14 +10,33 @@ import { decodeJwt } from 'jose'; import { getCookie } from 'cookies-next'; import { useRouter } from 'next/router' import { BsFillChatFill } from 'react-icons/bs'; +import randomColor from 'randomcolor' import Addperson from './additionalpeople'; +const backendroot = process.env.NEXT_PUBLIC_BACKEND_ROOT function getid() { const JWTtoken = getCookie('usercookie'); const { id } = decodeJwt(JWTtoken) return id } +export async function getServerSideProps() { + let endpoint = backendroot + 'api/user/id?search=' + let id = getid() + const options = { + // The method is POST because we are sending data. + method: 'GET', + // Tell the server we're sending JSON. + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + getCookie('usercookie') + } + } + //Fetch data from external API + const res = await fetch(endpoint + id, options) + const data = await res.json() + return { props: { data } } +} function Menuelement(props) { const [snapshot, loading, error] = useCollection(collection(db, "chats")) @@ -49,7 +68,9 @@ function Menuelement(props) { ) ) } -const Sidebar = ({ children }) => { + + +const Sidebar = ({props, children }) => { const [open, setOpen] = useState(false); const [confirmLoading, setConfirmLoading] = useState(false); const [addUser, setAddUser] = useState([]); @@ -60,10 +81,33 @@ const Sidebar = ({ children }) => { let submitnewchat = async (event) => { - console.log(chatTitle) - console.log(addUser) + try { - await addDoc(collection(db, "chats"), {name: chatTitle, rectime: new Date(), users: [getid(), addUser[0].key]}) + let gotuserdata = await getServerSideProps() + gotuserdata = gotuserdata['props']['data'][0] + var userdata = {}; + var users = [] + users.push(gotuserdata._id) + userdata[gotuserdata._id] = { + 'full': gotuserdata.Rank + " " + gotuserdata.Name, + 'rank': gotuserdata.Rank, + 'name': gotuserdata.Name, + 'color': randomColor({luminosity: 'dark', hue: 'random'}) + + } + for (let i = 0; i < addUser.length; i++) { + let splitdata = addUser[i].label.split(' ') + users.push(addUser[i].key) + userdata[addUser[i].key] = { + 'full': addUser[i].label, + 'rank': splitdata[0], + 'name': splitdata[1], + 'color': randomColor({luminosity: 'dark', hue: 'random'}), + } + } + await addDoc(collection(db, "chats"), + {name: chatTitle, + rectime: new Date(), users: users, userdata: userdata}) setOpen(false); } catch { seterrormsg('Error when creating chat room') @@ -124,4 +168,7 @@ const Sidebar = ({ children }) => { } + + + export default Sidebar; \ No newline at end of file diff --git a/front-end/web-next/package-lock.json b/front-end/web-next/package-lock.json index 72114e01..785f984e 100644 --- a/front-end/web-next/package-lock.json +++ b/front-end/web-next/package-lock.json @@ -23,6 +23,7 @@ "formik-antd": "^2.0.4", "jose": "^4.10.0", "next": "^12.3.1", + "randomcolor": "^0.6.2", "react": "18.2.0", "react-dom": "18.2.0", "react-draggable": "^4.4.5", @@ -30,6 +31,7 @@ "react-icons": "^4.4.0", "react-infinite-scroll-component": "^6.1.0", "react-organizational-chart": "^2.2.0", + "react-router": "^6.4.2", "util": "^0.12.4", "uuid": "^9.0.0" }, @@ -1939,6 +1941,14 @@ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, + "node_modules/@remix-run/router": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.2.tgz", + "integrity": "sha512-GRSOFhJzjGN+d4sKHTMSvNeUPoZiDHWmRnXfzaxrqe7dE/Nzlc8BiMSJdLDESZlndM7jIUrZ/F4yWqVYlI0rwQ==", + "engines": { + "node": ">=14" + } + }, "node_modules/@rushstack/eslint-patch": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", @@ -5235,6 +5245,11 @@ ], "license": "MIT" }, + "node_modules/randomcolor": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/randomcolor/-/randomcolor-0.6.2.tgz", + "integrity": "sha512-Mn6TbyYpFgwFuQ8KJKqf3bqqY9O1y37/0jgSK/61PUxV4QfIMv0+K2ioq8DfOjkBslcjwSzRfIDEXfzA9aCx7A==" + }, "node_modules/rc-align": { "version": "4.0.12", "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-4.0.12.tgz", @@ -5914,6 +5929,20 @@ "react-dom": ">= 16.12.0" } }, + "node_modules/react-router": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.2.tgz", + "integrity": "sha512-Rb0BAX9KHhVzT1OKhMvCDMw776aTYM0DtkxqUBP8dNBom3mPXlfNs76JNGK8wKJ1IZEY1+WGj+cvZxHVk/GiKw==", + "dependencies": { + "@remix-run/router": "1.0.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, "node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -8258,6 +8287,11 @@ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, + "@remix-run/router": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.2.tgz", + "integrity": "sha512-GRSOFhJzjGN+d4sKHTMSvNeUPoZiDHWmRnXfzaxrqe7dE/Nzlc8BiMSJdLDESZlndM7jIUrZ/F4yWqVYlI0rwQ==" + }, "@rushstack/eslint-patch": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", @@ -10537,6 +10571,11 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "randomcolor": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/randomcolor/-/randomcolor-0.6.2.tgz", + "integrity": "sha512-Mn6TbyYpFgwFuQ8KJKqf3bqqY9O1y37/0jgSK/61PUxV4QfIMv0+K2ioq8DfOjkBslcjwSzRfIDEXfzA9aCx7A==" + }, "rc-align": { "version": "4.0.12", "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-4.0.12.tgz", @@ -11007,6 +11046,14 @@ "@emotion/css": "^11.7.1" } }, + "react-router": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.2.tgz", + "integrity": "sha512-Rb0BAX9KHhVzT1OKhMvCDMw776aTYM0DtkxqUBP8dNBom3mPXlfNs76JNGK8wKJ1IZEY1+WGj+cvZxHVk/GiKw==", + "requires": { + "@remix-run/router": "1.0.2" + } + }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", diff --git a/front-end/web-next/package.json b/front-end/web-next/package.json index e7fecc97..a6cbe4e7 100644 --- a/front-end/web-next/package.json +++ b/front-end/web-next/package.json @@ -26,6 +26,7 @@ "formik-antd": "^2.0.4", "jose": "^4.10.0", "next": "^12.3.1", + "randomcolor": "^0.6.2", "react": "18.2.0", "react-dom": "18.2.0", "react-draggable": "^4.4.5", @@ -33,6 +34,7 @@ "react-icons": "^4.4.0", "react-infinite-scroll-component": "^6.1.0", "react-organizational-chart": "^2.2.0", + "react-router": "^6.4.2", "util": "^0.12.4", "uuid": "^9.0.0" }, diff --git a/front-end/web-next/pages/messages.js b/front-end/web-next/pages/messages.js index b6511385..c340e9b0 100644 --- a/front-end/web-next/pages/messages.js +++ b/front-end/web-next/pages/messages.js @@ -2,10 +2,10 @@ import Sidebar from '../componenets/Chatsidebar' import Head from 'next/head' import { PageHeader, Image } from 'antd'; -function chatpage() { +function Chatpage({children}) { return <> - + {children} } -export default chatpage; \ No newline at end of file +export default Chatpage; \ No newline at end of file diff --git a/front-end/web-next/pages/messages/[id].js b/front-end/web-next/pages/messages/[id].js index 29d76c6e..cc9ad3e0 100644 --- a/front-end/web-next/pages/messages/[id].js +++ b/front-end/web-next/pages/messages/[id].js @@ -1,14 +1,156 @@ import Sidebar from '../../componenets/Chatsidebar' +import Chatpage from '../messages' import Head from 'next/head' -import styles from '../../styles/chat.module.css' +import { Avatar, Divider, Tooltip, Button, Popover } from 'antd'; +import styles from '../../styles/chatpage.module.css' import { PageHeader, Image } from 'antd'; +import React, { useEffect, useState } from 'react'; +import { useRouter } from "next/router" + function chatpage() { + const router = useRouter() + const { id } = router.query + console.log(id) return <> - -

hi!

-
+ +
+

Hi!

+
+

Participants:

+ + 상영 + K + K + + + +
+ +
+
+ {generatechatelement('mine', 'regular', 'helloworld!')} + {generatechatelement('mine', 'report', 'helloworld!')} + + {generatechatelement('theirs', 'regular', 'ajsdf;lahf')} + {generatechatelement('mine', 'secret', 'ajsdf;lahf')} + {generatechatelement('theirs', 'secret', 'ajsdf;lahf')} + + + +
+ +
} +function generatechatelement(which, type, content) { + if (which == 'mine') { + if (type == 'regular') { + return <> +
+ {content} +
+ + } else if (type == 'report') { + return <> +
+

[상황보고]

+ {content} +
+ + } else if (type == 'order') { + return <> +
+

[지시사항]

+ {content} +
+ + } else if (type == 'secret') { + function ScretText({ content }) { + const [isVisible, setIsVisible] = useState(false) + + return
setIsVisible(p => !p)} style={{ cursor: 'pointer' }}> +

[기밀사항]

+ {isVisible ? content : <> + 클릭해 주세요.} +
+ } + + return + + } + + } else if (which == 'theirs') { + if (type == "regular") { + return <> +
+
+ {content} +
+
+ 상영 +
상영
+
+ +
+ + + } + + else if (type == 'report') { + return <> +
+
+

[상황보고]

+ {content} +
+
+ 상영 +
상영
+
+ +
+ + } else if (type == 'order') { + return <> +
+
+

[상황보고]

+ {content} +
+
+ 상영 +
상영
+
+ +
+ + } else if (type == 'secret') { + function ScretText({ content }) { + const [isVisible, setIsVisible] = useState(false) + + return <>
setIsVisible(p => !p)} style={{ display: 'flex', alignItems: 'center', alignSelf: 'flex-end', cursor: 'pointer' }}> +
+

[기밀사항]

+ {isVisible ? content : <> + 클릭해 주세요.} +
+
+ 상영 +
상영
+
+
+ + } + + return + + } + + + } + +} + export default chatpage; \ No newline at end of file diff --git a/front-end/web-next/styles/chat.module.css b/front-end/web-next/styles/chat.module.css index 7b188968..47f451c9 100644 --- a/front-end/web-next/styles/chat.module.css +++ b/front-end/web-next/styles/chat.module.css @@ -6,6 +6,7 @@ display: flex; height: 100px; border-bottom: 0.5px lightgrey solid; + width: 360px; } .menuelemtitle { font-size: 20px; diff --git a/front-end/web-next/styles/chatpage.module.css b/front-end/web-next/styles/chatpage.module.css new file mode 100644 index 00000000..126f86c7 --- /dev/null +++ b/front-end/web-next/styles/chatpage.module.css @@ -0,0 +1,44 @@ +.header { + width: calc(100vw - 640px); + height: 55px; + background-color: #e9e8e8; + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 15px; +} + +.participants { + display: flex; + align-items: center; + margin-right: 80px; +} +.title { + margin-left: 30px; +} + +.chatarea { + display: flex; + flex-direction: column; + width: 90%; + margin: auto; +} + +.mychatelem { + background-color: skyblue; + width: fit-content; + min-width: 100px; + border-radius: 10px; + padding: 8px; + margin: 1px; +} + +.theirchatelem { + background-color: greenyellow; + width: fit-content; + min-width: 100px; + border-radius: 10px; + padding: 8px; + margin: 1px; + margin-right: 13px; +} \ No newline at end of file diff --git a/front-end/web-next/styles/globals.css b/front-end/web-next/styles/globals.css index c30e8522..bbc3936b 100644 --- a/front-end/web-next/styles/globals.css +++ b/front-end/web-next/styles/globals.css @@ -18,6 +18,9 @@ body { h3{ margin: 0; } +h1 { + margin: 0; +} div { margin: 0; } From df8d15f6eb109fbbaad769350004303818f8050a Mon Sep 17 00:00:00 2001 From: hyeongmin Kim <113012760+gudmin0526@users.noreply.github.com> Date: Sat, 22 Oct 2022 11:21:14 +0000 Subject: [PATCH 43/48] Feat: Add getReportApi and test it. --- .../{fetchReportApi.js => getReportApi.js} | 20 +--- .../app/src/apis/unit/updateUnitLogoApi.js | 6 +- .../app/src/components/ChatListItem/style.js | 5 +- .../app/src/components/ImagePicker/index.js | 12 +- .../app/src/components/ImagePicker/style.js | 2 +- .../app/src/components/MyButton/index.js | 13 ++- .../app/src/components/ReportComment/style.js | 2 - .../app/src/components/ReportGroup/index.js | 21 ++-- .../app/src/components/ReportHeader/index.js | 11 +- .../app/src/components/ReportHeader/style.js | 2 +- .../src/components/ReportListItem/index.js | 53 +++++++-- .../src/components/ReportListItem/style.js | 1 - .../app/src/components/Searchbar/index.js | 34 ++++++ .../app/src/components/Searchbar/style.js | 25 +++++ .../app/src/components/UserCard/index.js | 4 +- .../app/src/components/UserCard/style.js | 4 +- .../screens/chat-screens/ChatListScreen.js | 39 ++----- .../report-screens/CreateReportScreen.js | 2 +- .../report-screens/RecdReportScreen.js | 105 ++++++++++-------- .../screens/report-screens/ReportScreen.js | 70 +++++++----- .../report-screens/SentReportScreen.js | 4 +- .../screens/setting-screens/SettingScreen.js | 2 +- .../screens/setting-screens/SysMgtScreen.js | 94 ++++++++++++---- .../screens/setting-screens/UnitAddScreen.js | 7 +- .../screens/setting-screens/UnitMgtScreen.js | 18 ++- .../screens/setting-screens/UserMgtScreen.js | 13 ++- .../setting-screens/UserUpdateScreen.js | 9 +- 27 files changed, 377 insertions(+), 201 deletions(-) rename front-end/app/src/apis/report/{fetchReportApi.js => getReportApi.js} (56%) create mode 100644 front-end/app/src/components/Searchbar/index.js create mode 100644 front-end/app/src/components/Searchbar/style.js diff --git a/front-end/app/src/apis/report/fetchReportApi.js b/front-end/app/src/apis/report/getReportApi.js similarity index 56% rename from front-end/app/src/apis/report/fetchReportApi.js rename to front-end/app/src/apis/report/getReportApi.js index ce9993f6..111d189a 100644 --- a/front-end/app/src/apis/report/fetchReportApi.js +++ b/front-end/app/src/apis/report/getReportApi.js @@ -1,32 +1,20 @@ import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' -const fetchReportApi = async ({ - Type, - Reportsystems, - Additionalpeople, - Content, - Title, -}) => { +const getReportApi = async () => { try { - const res = await fetch(URL, { + const res = await fetch(URL + '/api/report', { method: 'GET', headers: { 'Content-Type': 'application/json', Accept: 'application/json', Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, }, - body: { - Type, - Reportsystems, - Additionalpeople, - Content, - Title, - }, }) + return res.json() } catch (error) { console.log(error) } } -export default fetchReportApi +export default getReportApi diff --git a/front-end/app/src/apis/unit/updateUnitLogoApi.js b/front-end/app/src/apis/unit/updateUnitLogoApi.js index fff858ce..be1f04a9 100644 --- a/front-end/app/src/apis/unit/updateUnitLogoApi.js +++ b/front-end/app/src/apis/unit/updateUnitLogoApi.js @@ -1,15 +1,17 @@ import URL from '../../../url' import asyncStorage from '@react-native-async-storage/async-storage' -const updateUnitLogoApi = async ({ Logo }) => { +const updateUnitLogoApi = async ({ Logo, Unit }) => { + console.log(Logo, Unit) try { const res = await fetch(URL + '/api/unit/logo', { - method: 'POST', + method: 'PUT', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${await asyncStorage.getItem('roksrs-token')}`, }, body: JSON.stringify({ Logo }), + user: JSON.stringify({ Unit }), }) return res.json() } catch (error) { diff --git a/front-end/app/src/components/ChatListItem/style.js b/front-end/app/src/components/ChatListItem/style.js index 0c63959d..a88c9e8c 100644 --- a/front-end/app/src/components/ChatListItem/style.js +++ b/front-end/app/src/components/ChatListItem/style.js @@ -4,10 +4,11 @@ import { Colors } from 'react-native-paper' const styles = StyleSheet.create({ container: { flexDirection: 'row', - width: '100%', + width: '97%', justifyContent: 'space-between', alignSelf: 'center', - padding: 10, + paddingVertical: 10, + paddingHorizontal: 3, backgroundColor: 'white', borderColor: Colors.grey200, borderBottomWidth: 1, diff --git a/front-end/app/src/components/ImagePicker/index.js b/front-end/app/src/components/ImagePicker/index.js index 5f22b29d..5d0626e9 100644 --- a/front-end/app/src/components/ImagePicker/index.js +++ b/front-end/app/src/components/ImagePicker/index.js @@ -3,7 +3,7 @@ import * as ExpoImagePicker from 'expo-image-picker' import { Pressable, Image, Text, View } from 'react-native' import { styles } from './style' -export function ImagePicker({ imageUrl, setImageUrl }) { +export function ImagePicker(props) { const [status, requestPermission] = ExpoImagePicker.useMediaLibraryPermissions() @@ -25,15 +25,15 @@ export function ImagePicker({ imageUrl, setImageUrl }) { return null // 이미지 업로드 취소한 경우 } console.log(result) - setImageUrl(result.uri) + props.setImageUrl(result.uri) } return ( - - - {!imageUrl && ( + + + {!props.imageUrl && ( - {`부대 마크 변경하려면 클릭`} + {props.text} )} diff --git a/front-end/app/src/components/ImagePicker/style.js b/front-end/app/src/components/ImagePicker/style.js index fb35346a..23b55838 100644 --- a/front-end/app/src/components/ImagePicker/style.js +++ b/front-end/app/src/components/ImagePicker/style.js @@ -6,7 +6,7 @@ export const styles = StyleSheet.create({ pressable: { justifyContent: 'center', alignItems: 'center', - marginBottom: window.height * 0.04, + marginBottom: window.height * 0.03, }, image: { width: 0.8 * window.width, diff --git a/front-end/app/src/components/MyButton/index.js b/front-end/app/src/components/MyButton/index.js index aba4fed4..0bdb7957 100644 --- a/front-end/app/src/components/MyButton/index.js +++ b/front-end/app/src/components/MyButton/index.js @@ -1,5 +1,5 @@ import React from 'react' -import { View, TouchableOpacity, Text } from 'react-native' +import { TouchableOpacity, Text } from 'react-native' import { useNavigation } from '@react-navigation/native' import { useNunitoFonts } from '../../hooks/useNunitoFonts' import { styles } from './style' @@ -9,10 +9,11 @@ export function MyButton(props) { const navigation = useNavigation() return ( - - - {props.text} - - + + {props.text} + ) } diff --git a/front-end/app/src/components/ReportComment/style.js b/front-end/app/src/components/ReportComment/style.js index 94cab80c..be5217d4 100644 --- a/front-end/app/src/components/ReportComment/style.js +++ b/front-end/app/src/components/ReportComment/style.js @@ -4,8 +4,6 @@ import { Colors } from 'react-native-paper' export const styles = StyleSheet.create({ contentView: { width: '97%', - borderBottomWidth: 1, - borderColor: Colors.grey400, paddingTop: 5, paddingBottom: 3, paddingLeft: 3, diff --git a/front-end/app/src/components/ReportGroup/index.js b/front-end/app/src/components/ReportGroup/index.js index 02263735..be7ad1f4 100644 --- a/front-end/app/src/components/ReportGroup/index.js +++ b/front-end/app/src/components/ReportGroup/index.js @@ -1,5 +1,5 @@ import React from 'react' -import { FlatList, Text, Image } from 'react-native' +import { FlatList, Text, Image, View } from 'react-native' import { styles } from './style' import { useNunitoFonts } from '../../hooks/useNunitoFonts' import { UserCard } from '../UserCard' @@ -11,26 +11,29 @@ const ItemSeparator = () => ( /> ) -const renderItem = ({ item }) => ( - +const renderItem = ({ item, props }) => ( + ) export function ReportGroup(props) { let [fontsLoaded] = useNunitoFonts() return ( - <> + renderItem({ item, props })} contentContainerStyle={styles.container} horizontal={true} ItemSeparatorComponent={ItemSeparator} showsHorizontalScrollIndicator={false} /> - - {props.Title === 'onDuty' ? '당직계통 보고체계' : '본부중대 보고체계'} - - + {props.Title} + ) } diff --git a/front-end/app/src/components/ReportHeader/index.js b/front-end/app/src/components/ReportHeader/index.js index 90f7d633..5acfd441 100644 --- a/front-end/app/src/components/ReportHeader/index.js +++ b/front-end/app/src/components/ReportHeader/index.js @@ -11,16 +11,19 @@ export function ReportHeader(props) { {props.Title} - {props.isEnd ? '[종결]' : '[미종결]'} + {props.Status === 'Resolved' ? '[종결]' : '[미종결]'} 중요도: - {props.severity} + {props.Severity} {props.date} diff --git a/front-end/app/src/components/ReportHeader/style.js b/front-end/app/src/components/ReportHeader/style.js index 8262c41d..3c3a6dc8 100644 --- a/front-end/app/src/components/ReportHeader/style.js +++ b/front-end/app/src/components/ReportHeader/style.js @@ -20,7 +20,7 @@ export const styles = StyleSheet.create({ title: { fontSize: 20, }, - isEnd: { + status: { fontSize: 19, marginLeft: 5, }, diff --git a/front-end/app/src/components/ReportListItem/index.js b/front-end/app/src/components/ReportListItem/index.js index 7011c750..3ca84c45 100644 --- a/front-end/app/src/components/ReportListItem/index.js +++ b/front-end/app/src/components/ReportListItem/index.js @@ -1,15 +1,37 @@ -import React from 'react' +import React, { useState, useEffect } from 'react' import { TouchableOpacity, Text, View } from 'react-native' import { Card, Paragraph, Colors } from 'react-native-paper' import { useNunitoFonts } from '../../hooks/useNunitoFonts' +import moment from 'moment' import { useNavigation } from '@react-navigation/native' import { styles } from './style' export function ReportListItem(props) { - const { Title, isEnd, Content, severity, date, Type } = props + const { + Title, + Status, + Content, + Severity, + createdAt, + Type, + ReportingSystem, + Invited, + Comments, + User, + } = props - let [fontsLoaded] = useNunitoFonts() + const [date, setDate] = useState('') + useEffect(() => { + if (createdAt) { + setDate( + moment(createdAt.slice(0, 10) + ' ' + createdAt.slice(11, 19)).format( + 'YYYY년 MM월 DD일 hh시 mm분' + ) + ) + } + }) + let [fontsLoaded] = useNunitoFonts() const navigation = useNavigation() const goReportScreen = () => { @@ -17,11 +39,15 @@ export function ReportListItem(props) { screen: 'ReportScreen', params: { Title, - isEnd, + Status, Content, - severity, + Severity, date, Type, + ReportingSystem, + Invited, + Comments, + User, }, }) } @@ -31,14 +57,21 @@ export function ReportListItem(props) { onPress={goReportScreen} style={[ styles.cardListItem, - { borderColor: isEnd ? Colors.green600 : Colors.red300 }, + { + borderColor: Status === 'Resolved' ? Colors.green600 : Colors.red300, + }, ]} > {Title} - - {isEnd ? '[종결]' : '[미종결]'} + + {Status === 'Resolved' ? '[종결]' : '[미종결]'} 중요도: - {severity} - {date} + {Severity} + {date && date} diff --git a/front-end/app/src/components/ReportListItem/style.js b/front-end/app/src/components/ReportListItem/style.js index 21750ca8..0b3d63de 100644 --- a/front-end/app/src/components/ReportListItem/style.js +++ b/front-end/app/src/components/ReportListItem/style.js @@ -19,7 +19,6 @@ export const styles = StyleSheet.create({ fontSize: 13, fontFamily: 'NunitoSans_400Regular', color: Colors.grey800, - flex: 1, flexWrap: 'wrap', }, flexRow: { diff --git a/front-end/app/src/components/Searchbar/index.js b/front-end/app/src/components/Searchbar/index.js new file mode 100644 index 00000000..c1c591a4 --- /dev/null +++ b/front-end/app/src/components/Searchbar/index.js @@ -0,0 +1,34 @@ +import React, { useState } from 'react' +import { View, TextInput } from 'react-native' +import { IconButton, Colors } from 'react-native-paper' +import { styles, borderColor } from './style' + +export function Searchbar(props) { + const [focus, setFocus] = useState(false) + + return ( + + + props.setQuery(query)} + style={styles.input} + onFocus={() => setFocus(true)} + onBlur={() => setFocus(false)} + value={props.value} + /> + {props.value && ( + props.setQuery('')} + /> + )} + + ) +} diff --git a/front-end/app/src/components/Searchbar/style.js b/front-end/app/src/components/Searchbar/style.js new file mode 100644 index 00000000..ff7a2cf4 --- /dev/null +++ b/front-end/app/src/components/Searchbar/style.js @@ -0,0 +1,25 @@ +import { StyleSheet } from 'react-native' +import { Colors } from 'react-native-paper' + +export const styles = StyleSheet.create({ + searchBar: { + width: '92%', + height: 45, + backgroundColor: Colors.grey100, + elevation: 4, + alignSelf: 'center', + flexDirection: 'row', + alignItems: 'center', + borderRadius: 8, + borderBottomWidth: 1, + }, + input: { + fontSize: 15, + flex: 1, + }, +}) + +export const borderColor = (focus) => + StyleSheet.create({ + borderBottomColor: focus ? '#008275' : Colors.grey400, + }) diff --git a/front-end/app/src/components/UserCard/index.js b/front-end/app/src/components/UserCard/index.js index 14bc77bf..203fa64c 100644 --- a/front-end/app/src/components/UserCard/index.js +++ b/front-end/app/src/components/UserCard/index.js @@ -7,8 +7,8 @@ export function UserCard(props) { let [fontsLoaded] = useNunitoFonts() return ( - - + + {props.name} {props.position} diff --git a/front-end/app/src/components/UserCard/style.js b/front-end/app/src/components/UserCard/style.js index d1d26ddf..0a87ea78 100644 --- a/front-end/app/src/components/UserCard/style.js +++ b/front-end/app/src/components/UserCard/style.js @@ -6,13 +6,15 @@ export const styles = StyleSheet.create({ borderRadius: 6, alignItems: 'center', paddingVertical: 5, - width: 75, + paddingHorizontal: 3, + width: 70, marginBottom: 2, backgroundColor: Colors.grey200, elevation: 3, }, image: { marginBottom: 5, + backgroundColor: Colors.green400, }, title: { fontSize: 12, diff --git a/front-end/app/src/screens/chat-screens/ChatListScreen.js b/front-end/app/src/screens/chat-screens/ChatListScreen.js index 0fa3dbc7..d7e5534c 100644 --- a/front-end/app/src/screens/chat-screens/ChatListScreen.js +++ b/front-end/app/src/screens/chat-screens/ChatListScreen.js @@ -5,10 +5,10 @@ import { Colors, IconButton } from 'react-native-paper' import { ChatListItem } from '../../components/ChatListItem' import userData from '../../data/userData' import fetchChatApi from '../../apis/fetchChatApi' +import { Searchbar } from '../../components/Searchbar' export function ChatListScreen() { const [query, setQuery] = useState('') - const [focus, setFocus] = useState(false) useEffect(() => { const fetchChatList = async () => { const res = await fetchChatApi() @@ -17,8 +17,6 @@ export function ChatListScreen() { fetchChatList() }, []) - const onChangeSearch = (query) => setQuery(query) - const renderItem = ({ item }) => ( + - - setFocus(true)} - onBlur={() => setFocus(false)} - /> - + } /> @@ -57,20 +46,6 @@ export function ChatListScreen() { const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: Colors.white, alignItems: 'center' }, - searchBar: { - width: '92%', - backgroundColor: Colors.grey100, - height: 45, - elevation: 4, - alignSelf: 'center', - flexDirection: 'row', - alignItems: 'center', - borderRadius: 8, - borderBottomWidth: 1, - }, - input: { - fontSize: 15, - }, }) const borderColor = (focus) => diff --git a/front-end/app/src/screens/report-screens/CreateReportScreen.js b/front-end/app/src/screens/report-screens/CreateReportScreen.js index 0bd97d43..bc96f57a 100644 --- a/front-end/app/src/screens/report-screens/CreateReportScreen.js +++ b/front-end/app/src/screens/report-screens/CreateReportScreen.js @@ -120,7 +120,7 @@ export function CreateReportScreen() { right={ { diff --git a/front-end/app/src/screens/report-screens/RecdReportScreen.js b/front-end/app/src/screens/report-screens/RecdReportScreen.js index 857fcd7f..4c4540f3 100644 --- a/front-end/app/src/screens/report-screens/RecdReportScreen.js +++ b/front-end/app/src/screens/report-screens/RecdReportScreen.js @@ -1,58 +1,73 @@ -import React from 'react' +import React, { useState, useEffect } from 'react' import { ReportListItem } from '../../components/ReportListItem' // prettier-ignore -import { SafeAreaView, StyleSheet, ScrollView } from 'react-native' +import { SafeAreaView, StyleSheet, ScrollView, ActivityIndicator, View } from 'react-native' import { Colors, FAB } from 'react-native-paper' import { useNavigation } from '@react-navigation/native' -import moment from 'moment' -import fetchReportApi from '../../apis/report/fetchReportApi' +import getReportApi from '../../apis/report/getReportApi' -const { Title, isEnd, Content, severity, date, Type } = { - Title: '3초소 거수자 발견', - isEnd: false, - Content: `충성! 당직사령님, 3초소에 사복을 입은 거수자가 나타났습니다.\n무기는 소지하고 있지 않은 것으로 보이며, 위병소 앞에서 두리번 거리고 있습니다.\n현재 경계중이며, 추가사항 발생시 보고드리겠습니다.`, - severity: 3, - date: `${moment().subtract(6, 'days').format('YYYY-MM-DD hh:mm')}`, - Type: '긴급상황', -} +// const { Title, Status, Content, severity, date, Type } = { +// Title: '3초소 거수자 발견', +// Status: 'Resolved', +// Content: `충성! 당직사령님, 3초소에 사복을 입은 거수자가 나타났습니다.\n무기는 소지하고 있지 않은 것으로 보이며, 위병소 앞에서 두리번 거리고 있습니다.\n현재 경계중이며, 추가사항 발생시 보고드리겠습니다.`, +// severity: 3, +// date: `${moment().subtract(6, 'days').format('YYYY-MM-DD hh:mm')}`, +// Type: '긴급상황', +// } export function RecdReportScreen() { + const [reports, setReports] = useState([]) + const [isLoading, setIsLoading] = useState(true) + + const getReportHandler = async () => { + setReports(await getReportApi()) + } + + useEffect(() => { + getReportHandler() + setIsLoading(false) + }, []) + const navigation = useNavigation() - // const [reports, setReports] = useState(() => fetchReportHandler()) return ( - - - - - - navigation.navigate('ReportNavigator', { - screen: 'CreateReportScreen', - }) - } - style={styles.fab} - color="white" - /> + {isLoading ? ( + + ) : ( + + + {reports.map((report) => ( + + ))} + + + navigation.navigate('ReportNavigator', { + screen: 'CreateReportScreen', + }) + } + style={styles.fab} + color="white" + /> + + )} ) } @@ -63,8 +78,10 @@ const styles = StyleSheet.create({ backgroundColor: Colors.grey200, paddingTop: 3, paddingBottom: 5, + justifyContent: 'center', }, scrollView: { + flex: 1, width: '100%', alignItems: 'center', }, diff --git a/front-end/app/src/screens/report-screens/ReportScreen.js b/front-end/app/src/screens/report-screens/ReportScreen.js index 2aab3d91..cea72ed6 100644 --- a/front-end/app/src/screens/report-screens/ReportScreen.js +++ b/front-end/app/src/screens/report-screens/ReportScreen.js @@ -11,13 +11,24 @@ import { useRecoilState } from 'recoil' import { userState } from '../../states/userState' import addCommentApi from '../../apis/report/addCommentApi' -const addCommentHandler = async ({ Type, Content, Title, _id }) => { - const res = await addCommentApi({ Type, Content, Title, _id }) - console.log(res) -} - export function ReportScreen({ route }) { - const { Title, isEnd, Content, severity, date, Type } = route.params + const addCommentHandler = async ({ Type, Content, Title, _id }) => { + const res = await addCommentApi({ Type, Content, Title, _id }) + console.log(res) + } + + const { + Title, + Status, + Content, + Severity, + date, + Type, + ReportingSystem, + Invited, + Comments, + User, + } = route.params const [userMe, setUserMe] = useRecoilState(userState) @@ -39,8 +50,8 @@ export function ReportScreen({ route }) { @@ -48,7 +59,7 @@ export function ReportScreen({ route }) { style={{ width: '97%', borderBottomWidth: 1, - borderColor: Colors.grey700, + borderColor: Colors.grey500, }} > @@ -58,16 +69,25 @@ export function ReportScreen({ route }) { ) - const renderItem = ({ item }) => { - return ( - - ) - } + const ItemSeparator = () => ( + + ) + + const renderItem = ({ item }) => ( + + ) return ( @@ -75,7 +95,9 @@ export function ReportScreen({ route }) { ListHeaderComponent={ListHeaderComponent} data={comments} renderItem={renderItem} + ItemSeparatorComponent={ItemSeparator} showsVerticalScrollIndicator={false} + contentContainerStyle={{ paddingBottom: 10 }} /> { setComments([ ...comments, @@ -140,12 +162,10 @@ const styles = StyleSheet.create({ flex: 1, backgroundColor: Colors.white, alignItems: 'center', - paddingBottom: 60, }, commentView: { - bottom: 0, - position: 'absolute', width: '98%', + paddingTop: 5, justifyContent: 'center', flexDirection: 'row', }, @@ -179,5 +199,5 @@ const styles = StyleSheet.create({ const borderColor = (focus) => StyleSheet.create({ - borderBottomColor: focus ? Colors.green500 : Colors.grey400, + borderBottomColor: focus ? '#008275' : Colors.grey400, }) diff --git a/front-end/app/src/screens/report-screens/SentReportScreen.js b/front-end/app/src/screens/report-screens/SentReportScreen.js index 88b58880..5ac35012 100644 --- a/front-end/app/src/screens/report-screens/SentReportScreen.js +++ b/front-end/app/src/screens/report-screens/SentReportScreen.js @@ -1,11 +1,11 @@ -import React from 'react' +import React, { useState } from 'react' import { ReportListItem } from '../../components/ReportListItem' // prettier-ignore import { SafeAreaView, StyleSheet, ScrollView } from 'react-native' import { Colors, FAB } from 'react-native-paper' import { useNavigation } from '@react-navigation/native' import moment from 'moment' -import fetchReportApi from '../../apis/report/fetchReportApi' +import getReportApi from '../../apis/report/getReportApi' const { Title, isEnd, Content, severity, date, Type } = { Title: '3초소 거수자 발견', diff --git a/front-end/app/src/screens/setting-screens/SettingScreen.js b/front-end/app/src/screens/setting-screens/SettingScreen.js index ddd0a8b8..ea1e2836 100644 --- a/front-end/app/src/screens/setting-screens/SettingScreen.js +++ b/front-end/app/src/screens/setting-screens/SettingScreen.js @@ -47,7 +47,7 @@ export function SettingScreen() { } /> } style={styles.listItem} onPress={() => diff --git a/front-end/app/src/screens/setting-screens/SysMgtScreen.js b/front-end/app/src/screens/setting-screens/SysMgtScreen.js index 97a9d67f..18f314ab 100644 --- a/front-end/app/src/screens/setting-screens/SysMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/SysMgtScreen.js @@ -1,21 +1,16 @@ import React, { useEffect, useState } from 'react' -import { SafeAreaView, ScrollView, StyleSheet } from 'react-native' -import { - Colors, - FAB, - Provider, - Modal, - Portal, - TextInput, -} from 'react-native-paper' +import { SafeAreaView, ScrollView, StyleSheet, View, Text } from 'react-native' +//prettier-ignore +import { Colors, FAB, Provider, Modal, Portal, TextInput } from 'react-native-paper' import { ReportGroup } from '../../components/ReportGroup' import DATA from '../../data/procData' -import { UserCard } from '../../components/UserCard' import getReportsysApi from '../../apis/report-sys/getReportsysApi' import addReportsysApi from '../../apis/report-sys/addReportsysApi' import removeReportsysApi from '../../apis/report-sys/removeReportsysApi' +import searchUserApi from '../../apis/user/searchUserApi' import { useRecoilState } from 'recoil' import { userState } from '../../states/userState' +import { MyButton } from '../../components/MyButton' const ItemSeparator = () => ( setVisible(true) @@ -55,29 +57,56 @@ export function SysMgtScreen() { setReportsys(reportsys.filter((item) => item._id != _id)) } + const searchUserHandler = async ({ query }) => { + const res = await searchUserApi({ query }) + setUsers(users.concat(res)) + } + return ( - + + setTitle(text)} + /> { - setQuery(query) - }} - left={} + style={[styles.textInput]} + onChangeText={(query) => setQuery(query)} + right={ + + } + onSubmitEditing={() => {}} + activeUnderlineColor="#008275" /> + + + + - {/* {reportsys.map((sys) => )} */} - - + + - + addUnitHandler({ Unitname, Unitslogan, Logo })} diff --git a/front-end/app/src/screens/setting-screens/UnitMgtScreen.js b/front-end/app/src/screens/setting-screens/UnitMgtScreen.js index 55d4eb8a..815f41e8 100644 --- a/front-end/app/src/screens/setting-screens/UnitMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/UnitMgtScreen.js @@ -6,10 +6,14 @@ import { window } from '../../constants/layout' import updateUnitApi from '../../apis/unit/addUnitApi' import updateUnitLogoApi from '../../apis/unit/updateUnitLogoApi' import { MyButton } from '../../components/MyButton' +import { useRecoilState } from 'recoil' +import { userState } from '../../states/userState' export function UnitMgtScreen() { + const [userMe, setUserMe] = useRecoilState(userState) + const updateUnitHandler = useCallback(async ({ Unitname, Unitslogan }) => { - const res = await updateUnitApi({ Unitname, Unitslogan }) + const res = await updateUnitApi({ Unitname, Unitslogan, Unit: userMe.Unit }) if (res.Unitname) { Alert.alert('부대 정보 업데이트에 성공하였습니다.') } else { @@ -18,7 +22,7 @@ export function UnitMgtScreen() { }, []) const updateUnitLogoHandler = useCallback(async ({ Logo }) => { - const res = await updateUnitLogoApi({ Logo }) + const res = await updateUnitLogoApi({ Logo, Unit: userMe.Unit }) if (res.Unitname) { Alert.alert('부대 로고 업데이트에 성공하였습니다.') } else { @@ -45,15 +49,19 @@ export function UnitMgtScreen() { dense={true} activeUnderlineColor="#008275" onChangeText={(Unitslogan) => setUnitslogan(Unitslogan)} - style={styles.textInput} + style={[styles.textInput, { marginBottom: 5 }]} /> updateUnitHandler({ Unitname, Unitslogan })} - style={{ marginBottom: 30 }} + style={{ marginBottom: 50 }} + /> + - updateUnitLogoHandler({ Logo })} diff --git a/front-end/app/src/screens/setting-screens/UserMgtScreen.js b/front-end/app/src/screens/setting-screens/UserMgtScreen.js index 67e3e155..6c2b62b1 100644 --- a/front-end/app/src/screens/setting-screens/UserMgtScreen.js +++ b/front-end/app/src/screens/setting-screens/UserMgtScreen.js @@ -45,7 +45,14 @@ export function UserMgtScreen() { /> ))} - + + navigation.navigate('SettingNavigator', { screen: 'UserAddScreen' }) + } + /> ) } @@ -73,8 +80,8 @@ export const styles = StyleSheet.create({ height: 55, width: 55, position: 'absolute', - bottom: 50, - right: 20, + bottom: 25, + right: 25, }, image: { backgroundColor: Colors.grey500, diff --git a/front-end/app/src/screens/setting-screens/UserUpdateScreen.js b/front-end/app/src/screens/setting-screens/UserUpdateScreen.js index a97dda9b..60e49a95 100644 --- a/front-end/app/src/screens/setting-screens/UserUpdateScreen.js +++ b/front-end/app/src/screens/setting-screens/UserUpdateScreen.js @@ -117,7 +117,7 @@ export function UserUpdateScreen() { style={styles.textInput} placeholder={userMe.milNumber} > - + + - From 1b2c7c17453e6d0e3c1152a8914c86166a8e33bc Mon Sep 17 00:00:00 2001 From: Yunseong Choe <68419358+marunemo@users.noreply.github.com> Date: Sat, 22 Oct 2022 13:25:37 +0000 Subject: [PATCH 44/48] [Design]Style organizational chart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 조직도 간소화 디자인 변경 #60 --- front-end/web-next/componenets/Organogram.js | 5 ++++- front-end/web-next/styles/Organogram.module.css | 13 +++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/front-end/web-next/componenets/Organogram.js b/front-end/web-next/componenets/Organogram.js index 04691300..57777494 100644 --- a/front-end/web-next/componenets/Organogram.js +++ b/front-end/web-next/componenets/Organogram.js @@ -13,6 +13,9 @@ function renderNode(node, chooseNode) { return (
diff --git a/front-end/web-next/styles/Organogram.module.css b/front-end/web-next/styles/Organogram.module.css index 7c5e463c..0bf27b2b 100644 --- a/front-end/web-next/styles/Organogram.module.css +++ b/front-end/web-next/styles/Organogram.module.css @@ -2,6 +2,8 @@ width: auto; height: auto; padding: 0; + margin-left: 15px; + margin-right: 15px; border: transparent; border-radius: 30pt; background-color: transparent @@ -11,13 +13,14 @@ width: 100px; height: 100px; border: 1px solid #ddd; - border-radius: 100% + border-radius: 50px } .cardContent { - padding: 10px; - border: 1px solid #777; - border-radius: 30pt; + padding-right: 50px; + border: 0; + border-radius: 50pt; + box-shadow: inset 0 -3em 3em rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(0, 128, 128, 0.5), 0.3em 0.3em 1em rgba(0, 0, 0, 0.3); } .userName { @@ -32,5 +35,7 @@ } .userPosition { + color: #555; font-size: 13pt; + text-align: left; } \ No newline at end of file From a542c2a83a70b88968414c02db100a118fc95bd5 Mon Sep 17 00:00:00 2001 From: Yunseong Choe <68419358+marunemo@users.noreply.github.com> Date: Sat, 22 Oct 2022 13:59:54 +0000 Subject: [PATCH 45/48] [Design]Style orgainzational card and form MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 조직도 세부 내용 및 form 디자인 수정 #60 --- .../web-next/componenets/OrganizationCard.js | 10 +++++- .../web-next/componenets/OrganizationForm.js | 32 +++++++++++++------ .../styles/OrganizationCard.module.css | 17 ++++------ .../styles/OrganizationForm.module.css | 28 ++++++++++++++-- front-end/web-next/styles/globals.css | 6 ++++ 5 files changed, 70 insertions(+), 23 deletions(-) diff --git a/front-end/web-next/componenets/OrganizationCard.js b/front-end/web-next/componenets/OrganizationCard.js index a7c541e5..f00e93d1 100644 --- a/front-end/web-next/componenets/OrganizationCard.js +++ b/front-end/web-next/componenets/OrganizationCard.js @@ -19,6 +19,7 @@ function OrganizationCard(props) { return ( <> + +
{props.data.Name} {props.data.Rank}
-
{props.data.DoDID}
+ diff --git a/front-end/web-next/componenets/OrganizationForm.js b/front-end/web-next/componenets/OrganizationForm.js index a037c297..aee964bb 100644 --- a/front-end/web-next/componenets/OrganizationForm.js +++ b/front-end/web-next/componenets/OrganizationForm.js @@ -1,5 +1,5 @@ import { useState, useCallback, useEffect } from 'react'; -import { Modal, Image, Row, Col, Select } from 'antd'; +import { Modal, Image, Row, Col, Input, Select } from 'antd'; import Styles from '../styles/OrganizationForm.module.css'; function InfoElement(props) { @@ -14,8 +14,8 @@ function InfoElement(props) { function InputElement(props) { return (
-
{props.label}
- +
{props.label}
+
) } @@ -23,7 +23,7 @@ function InputElement(props) { function ParentSelectElement(props) { return (
-
{props.label}
+
{props.label}
serializedEdit('Name', event.target.value)} /> + + serializedEdit('Name', event.target.value)} + /> serializedEdit('DoDID', event.target.value)} /> + + + serializedEdit('DoDID', event.target.value)} /> + @@ -116,7 +130,7 @@ function OrganizationForm(props) { serializedEdit('MilNumber', event.target.value)} /> - + .ant-modal-content, +.organizationForm > .ant-modal-content { + border-radius: 30px; + padding: 5px; } \ No newline at end of file From b69121acd0bb90e459bfdec6f902580682ed2267 Mon Sep 17 00:00:00 2001 From: Yunseong Choe <68419358+marunemo@users.noreply.github.com> Date: Sat, 22 Oct 2022 14:05:51 +0000 Subject: [PATCH 46/48] [Design]Style button group MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 조직도 카드 및 form 버튼 스타일 변경 --- front-end/web-next/componenets/OrganizationCard.js | 2 ++ front-end/web-next/componenets/OrganizationForm.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/front-end/web-next/componenets/OrganizationCard.js b/front-end/web-next/componenets/OrganizationCard.js index f00e93d1..20b4fb2b 100644 --- a/front-end/web-next/componenets/OrganizationCard.js +++ b/front-end/web-next/componenets/OrganizationCard.js @@ -28,6 +28,7 @@ function OrganizationCard(props) { : (