jrshikoku/menu.js

699 lines
22 KiB
JavaScript

import React, { useRef, useState, useEffect } from "react";
import Carousel from "react-native-snap-carousel";
import {
Platform,
View,
LayoutAnimation,
ScrollView,
Linking,
Text,
TouchableOpacity,
} from "react-native";
import Constants from "expo-constants";
import { ListItem } from "native-base";
import Icon from "react-native-vector-icons/Entypo";
import * as Location from "expo-location";
import StatusbarDetect from "./StatusbarDetect";
import { useNavigation } from "@react-navigation/native";
import AutoHeightImage from "react-native-auto-height-image";
import { widthPercentageToDP as wp } from "react-native-responsive-screen";
import {
FontAwesome,
Foundation,
Ionicons,
MaterialCommunityIcons,
} from "@expo/vector-icons";
import LottieView from "lottie-react-native";
import { StationDeteilView } from "./components/ActionSheetComponents/StationDeteilView";
import LED_vision from "./components/発車時刻表/LED_vidion";
import Sign from "./components/駅名表/Sign";
import { UsefulBox } from "./components/atom/UsefulBox";
import { TicketBox } from "./components/atom/TicketBox";
import { TextBox } from "./components/atom/TextBox";
import { getStationList, lineList } from "./lib/getStationList";
import { JRSTraInfo } from "./components/ActionSheetComponents/JRSTraInfo";
import useInterval from "./lib/useInterval";
export default function Menu(props) {
const {
navigation: { navigate },
favoriteStation,
setFavoriteStation,
} = props;
const JRSTraInfoEXAcSR = useRef(null);
const StationBoardAcSR = useRef(null);
const navigation = useNavigation();
//位置情報
const [location, setLocation] = useState(null);
const [locationStatus, setLocationStatus] = useState(null);
useEffect(() => {
Location.requestForegroundPermissionsAsync().then((data) => {
setLocationStatus(data.status);
});
}, []);
useEffect(() => {
if (locationStatus !== "granted") return () => {};
getCurrentPosition();
}, [locationStatus]);
const getCurrentPosition = () => {
Location.getCurrentPositionAsync({}).then((location) =>
setLocation(location)
);
};
useInterval(() => {
if (locationStatus !== "granted") return () => {};
getCurrentPosition();
}, 5000);
const [originalStationList, setOriginalStationList] = useState();
useEffect(() => {
getStationList().then(setOriginalStationList);
}, []);
const [locationAndFavorite, setLocationAndFavorite] = useState([]);
useEffect(() => {
if (!favoriteStation) return () => {};
const data = favoriteStation.filter((d) =>
JSON.stringify(d) === JSON.stringify(currentStation) ? false : true
);
setLocationAndFavorite(data);
}, [currentStation, favoriteStation]);
useEffect(() => {
if (!(selectedCurrentStation < favoriteStation.length)) {
setSelectedCurrentStation(favoriteStation.length - 1);
carouselRef.current.snapToItem(favoriteStation.length - 1);
}
}, [favoriteStation]);
const [stationName, setStationName] = useState(undefined);
const [currentStation, setCurrentStation] = useState(undefined);
useEffect(() => {
if (!location) return () => {};
if (!originalStationList) return () => {};
const findStationEachLine = (selectLine) => {
const searchArea = 0.0015;
const _calcDistance = (from, to) => {
let lat = Math.abs(from.lat - to.lat);
let lng = Math.abs(from.lng - to.lng);
return Math.sqrt(lat * lat + lng * lng);
};
let NearStation = selectLine.filter(
(d) =>
_calcDistance(d, {
lat: location.coords.latitude,
lng: location.coords.longitude,
}) < searchArea
);
return NearStation;
};
let returnDataBase = lineList
.map((d) => findStationEachLine(originalStationList[d]))
.filter((d) => d.length > 0)
.reduce((pre, current) => {
pre.push(...current);
return pre;
}, []);
LayoutAnimation.easeInEaseOut();
if (returnDataBase.length) {
let currentStation = currentStation == undefined ? [] : currentStation;
if (currentStation.toString() != returnDataBase.toString()) {
setCurrentStation(returnDataBase);
}
} else {
setCurrentStation(undefined);
StationBoardAcSR.current?.hide();
}
}, [location, originalStationList]);
const [count, setCount] = useState(0);
const [delayData, setDelayData] = useState(undefined);
const [getTime, setGetTime] = useState(new Date());
const [loadingDelayData, setLoadingDelayData] = useState(true);
const carouselRef = useRef();
const scrollRef = useRef();
const [isScroll, setIsScroll] = useState(true);
const [selectedCurrentStation, setSelectedCurrentStation] = useState(0);
useEffect(() => {
fetch(
"https://script.google.com/macros/s/AKfycbyKxch7z7l8e07LXulRHqxjVoIiB13kcgvoToLE-rqlxLmLSKdlmqz0FI1F2EuA7Zfg/exec"
)
.then((response) => response.text())
.then((data) => setDelayData(data !== "" ? data.split("^") : null))
.then(LayoutAnimation.easeInEaseOut)
.then(() => setGetTime(new Date()))
.finally(() => setLoadingDelayData(false));
}, [loadingDelayData]);
return (
<View
style={{
height: "100%",
backgroundColor: "white",
paddingTop: Platform.OS == "ios" ? Constants.statusBarHeight : 0,
}}
>
<StatusbarDetect />
<TitleBar />
<ScrollView ref={scrollRef} scrollEnabled={isScroll}>
<TopMenuButton />
<TextBox
backgroundColor="#0099CC"
flex={1}
onPressButton={() =>
Linking.openURL(
"https://www.jr-shikoku.co.jp/02_information/suspension/sp/"
)
}
>
<Text style={{ color: "white", fontWeight: "bold", fontSize: 18 }}>
新型コロナウイルスに関するお知らせ
</Text>
<Text style={{ color: "white", fontSize: 15 }}>
列車の運行計画混雑状況感染症対策への取り組み
</Text>
</TextBox>
<Carousel
ref={carouselRef}
layout={"default"}
data={
originalStationList &&
(currentStation
? [currentStation, ...locationAndFavorite]
: locationAndFavorite)
}
sliderWidth={wp("100%")}
itemWidth={wp("80%")}
enableMomentum
callbackOffsetMargin={1000}
activeAnimationOptions={0.3}
onSnapToItem={(d) => {
setSelectedCurrentStation(d);
}}
renderItem={({ item, index }) => {
return (
<View style={{ marginVertical: 10 }} key={item[0].StationNumber}>
<Sign
currentStation={item}
originalStationList={originalStationList}
favoriteStation={favoriteStation}
setFavoriteStation={setFavoriteStation}
oP={StationBoardAcSR.current?.setModalVisible}
/>
</View>
);
}}
/>
{(currentStation || originalStationList) && (
<LED_vision
station={
originalStationList &&
(currentStation
? [currentStation, ...locationAndFavorite]
: locationAndFavorite)[selectedCurrentStation][0]
}
navigate={navigate}
/>
)}
<JRSTraInfoBox
JRSTraInfoEXAcSR={JRSTraInfoEXAcSR}
getTime={getTime}
setLoadingDelayData={setLoadingDelayData}
loadingDelayData={loadingDelayData}
delayData={delayData}
/>
<View style={{ flexDirection: "row" }}>
<TicketBox
backgroundColor={"#AD7FA8"}
icon={<Foundation name="ticket" color="white" size={50} />}
flex={1}
onPressButton={() =>
Linking.openURL("https://www.jr-eki.com/ticket/brand")
}
>
トクトク切符
</TicketBox>
<TicketBox
backgroundColor={"#8F5902"}
icon={<FontAwesome name="first-order" color="white" size={50} />}
flex={1}
onPressButton={() =>
Linking.openURL(
"https://www.jr-shikoku.co.jp/01_trainbus/event_train/sp/"
)
}
>
観光列車
</TicketBox>
<TicketBox
backgroundColor={"#888A85"}
icon={<Ionicons name="flag" color="white" size={50} />}
flex={1}
onPressButton={() =>
Linking.openURL("https://www.jr-eki.com/tour/brand")
}
>
旅行ツアー
</TicketBox>
</View>
<TextBox
backgroundColor="#0099CC"
flex={1}
onPressButton={() =>
Linking.openURL("https://www.jr-eki.com/smart-eki/index.html")
}
>
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
スマートえきちゃん
</Text>
<Text style={{ color: "white", fontSize: 18 }}>
JR四国のチケットレススマホアプリです
</Text>
</TextBox>
<TextBox
backgroundColor="#0099CC"
flex={1}
onPressButton={() =>
Linking.openURL(
"https://www.jr-shikoku.co.jp/sp/index.html#menu-box"
)
}
>
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
臨時列車などのお知らせ
</Text>
<Text style={{ color: "white", fontSize: 18 }}>
区間縮小計画運休イベント季節臨時列車など
</Text>
</TextBox>
<TextBox
backgroundColor="#0099CC"
flex={1}
onPressButton={() =>
Linking.openURL("https://www.jr-shikoku.co.jp/03_news/press/")
}
>
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
ニュースリリース
</Text>
<Text style={{ color: "white", fontSize: 18 }}>
公式プレス記事はこちら
</Text>
</TextBox>
<TextBox
backgroundColor="#0099CC"
flex={1}
onPressButton={() =>
Linking.openURL("https://www.jr-shikoku.co.jp/teiki/")
}
>
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
定期運賃計算
</Text>
<Text style={{ color: "white", fontSize: 18 }}>
通常/学生/快てき等はこちら
</Text>
</TextBox>
<TextBox
backgroundColor="#0099CC"
flex={1}
onPressButton={() =>
Linking.openURL("https://www.jr-shikoku.co.jp/04_company/group/sp/")
}
>
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
JR四国のお店サービス
</Text>
<Text style={{ color: "white", fontSize: 18 }}>
JR四国グループの施設をご案内
</Text>
</TextBox>
<View style={{ flexDirection: "row" }}>
<TouchableOpacity
style={{
flex: 1,
backgroundColor: "#729FCF",
borderColor: "#0099CC",
padding: 10,
borderWidth: 1,
margin: 2,
alignItems: "center",
}}
onPress={() => Linking.openURL("https://www.jr-odekake.net/smt/")}
>
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
時刻運賃計算
</Text>
<Text style={{ color: "white", fontWeight: "bold", fontSize: 18 }}>
(マイダイヤ)
</Text>
<Foundation name="yen" color="white" size={50} />
<Text style={{ color: "white" }}>
マイダイヤはJR西日本提供のサービスです
</Text>
</TouchableOpacity>
<TouchableOpacity
style={{
flex: 1,
backgroundColor: "#8AE234",
borderColor: "#0099CC",
padding: 10,
borderWidth: 1,
margin: 2,
alignItems: "center",
}}
onPress={() => Linking.openURL("tel:0570-00-4592")}
>
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
JR四国案内センター
</Text>
<Foundation name="telephone" color="white" size={50} />
<Text style={{ color: "white" }}>0570-00-4592</Text>
<Text style={{ color: "white" }}>(8:00~20:00 年中無休)</Text>
<Text style={{ color: "white" }}>(通話料がかかります)</Text>
</TouchableOpacity>
</View>
<View
style={{
backgroundColor: "#0099CC",
borderRadius: 10,
margin: 10,
borderColor: "black",
borderWidth: 2,
}}
>
<View
style={{ padding: 10, flexDirection: "row", alignItems: "center" }}
>
<MaterialCommunityIcons
name="twitter"
style={{ padding: 5 }}
color="white"
size={30}
/>
<Text style={{ fontSize: 30, fontWeight: "bold", color: "white" }}>
JR四国公式Twitter一族
</Text>
</View>
<View
style={{
padding: 10,
backgroundColor: "white",
borderBottomLeftRadius: 10,
borderBottomRightRadius: 10,
}}
>
{((data) =>
data.map((d) => (
<ListItem onPress={() => Linking.openURL(d.url)}>
<Text>{d.name}</Text>
<View style={{ flex: 1 }} />
<Icon name="chevron-right" size={20} />
</ListItem>
)))([
{
url: "https://twitter.com/JRshikoku_eigyo",
name: "JR四国営業部【公式】",
},
{
url: "https://twitter.com/JRshikoku_tokyo",
name: "JR四国 東京営業情報【公式】",
},
{
url: "https://twitter.com/JRshikoku_osaka",
name: "JR四国 大阪営業部【公式】",
},
{
url: "https://twitter.com/jr_shikoku_info",
name: "JR四国列車運行情報【公式】",
},
{
url: "https://twitter.com/Smile_Eki_Chan",
name: "すまいるえきちゃん♡JR四国【公式】",
},
{
url: "https://twitter.com/jrs_matsuyama",
name: "JR四国 松山駅 【公式】",
},
{
url: "https://twitter.com/jrshikoku_kochi",
name: "JR四国 高知駅【公式】",
},
{
url: "https://twitter.com/jr_tokust",
name: "JR四国 徳島駅【公式】",
},
{
url: "https://twitter.com/jrshikoku_uwjm",
name: "JR四国 宇和島駅【公式】",
},
{
url: "https://twitter.com/JRshikoku_wkoch",
name: "JR四国 ワープ高知支店【公式】",
},
{
url: "https://twitter.com/jrshikoku_nihaw",
name: "JR四国 ワープ新居浜営業所【公式】",
},
{
url: "https://twitter.com/Yoakemonogatari",
name: "志国土佐 時代の夜明けのものがたり【公式】",
},
])}
</View>
</View>
<Text style={{ fontWeight: "bold", fontSize: 20 }}>
このアプリについて
</Text>
<Text>
このアプリはXprocess(HARUKIN)が製作しているJR四国の完全非公式アシストアプリケーションですこのアプリに関することでのJR四国公式へ問合せすることはお控えください以下のTwitterよりお願いします
</Text>
<TextBox
backgroundColor="#CC0000"
flex={1}
onPressButton={() =>
Linking.openURL("https://twitter.com/Xprocess_main")
}
>
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
XprocessのTwitter
</Text>
<Text style={{ color: "white", fontSize: 18 }}>
制作運営のTwitterです
</Text>
</TextBox>
<TextBox
backgroundColor="black"
flex={1}
onPressButton={() => navigate("setting")}
>
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
アプリの設定
</Text>
<Text style={{ color: "white", fontSize: 18 }}>
アプリの設定画面を表示します
</Text>
</TextBox>
{/*
<SvgUri
width="200"
height="200"
source={require("./assets/トレインビジョン関係/1.svg")}
/> */}
</ScrollView>
<StationDeteilView
StationBoardAcSR={StationBoardAcSR}
currentStation={
originalStationList &&
(currentStation
? [currentStation, ...locationAndFavorite]
: locationAndFavorite)[selectedCurrentStation]
}
originalStationList={originalStationList}
favoriteStation={favoriteStation}
setFavoriteStation={setFavoriteStation}
/>
<JRSTraInfo
JRSTraInfoEXAcSR={JRSTraInfoEXAcSR}
getTime={getTime}
loadingDelayData={loadingDelayData}
setLoadingDelayData={setLoadingDelayData}
delayData={delayData}
/>
</View>
);
}
const TitleBar = () => {
return (
<View style={{ alignItems: "center" }}>
<TouchableOpacity
onPress={() => Linking.openURL("https://www.jr-shikoku.co.jp")}
>
<AutoHeightImage
source={require("./assets/Header.png")}
resizeMode="contain"
width={wp("100%")}
/>
</TouchableOpacity>
</View>
);
};
const TopMenuButton = () => {
const buttonList = [
{
backgroundColor: "#F89038",
icon: "train-car",
onPress: () =>
Linking.openURL("https://www.jr-shikoku.co.jp/01_trainbus/sp/"),
title: "駅・鉄道情報",
},
{
backgroundColor: "#EA4752",
icon: "google-spreadsheet",
onPress: () =>
Linking.openURL(
"https://www.jr-shikoku.co.jp/01_trainbus/jikoku/sp/#mainprice-box"
),
title: "運賃表",
},
{
backgroundColor: "#91C31F",
icon: "clipboard-list-outline",
onPress: () => Linking.openURL("https://www.jr-shikoku.co.jp/e5489/"),
title: "予約",
},
];
return (
<View style={{ flexDirection: "row" }}>
{buttonList.map((d, index) => (
<UsefulBox
backgroundColor={d.backgroundColor}
icon={d.icon}
flex={1}
onPressButton={d.onPress}
key={index + d.icon}
>
{d.title}
</UsefulBox>
))}
</View>
);
};
const JRSTraInfoBox = (props) => {
const {
JRSTraInfoEXAcSR,
getTime,
setLoadingDelayData,
loadingDelayData,
delayData,
} = props;
const styles = {
touch: {
backgroundColor: "#0099CC",
borderRadius: 5,
margin: 10,
borderColor: "black",
borderWidth: 2,
overflow: "hidden",
},
scroll: {
backgroundColor: "#0099CC",
borderRadius: 5,
maxHeight: 300,
},
bottom: {
position: "absolute",
top: 250,
alignItems: "center",
width: "100%",
height: 50,
backgroundColor: "#007FCC88",
},
box: {
padding: 10,
backgroundColor: "white",
borderBottomLeftRadius: 5,
borderBottomRightRadius: 5,
},
};
return (
<TouchableOpacity
onPress={JRSTraInfoEXAcSR.current?.setModalVisible}
style={styles.touch}
>
<ScrollView scrollEnabled={false} style={styles.scroll}>
<View
style={{ padding: 10, flexDirection: "row", alignItems: "center" }}
>
<Text style={{ fontSize: 30, fontWeight: "bold", color: "white" }}>
列車遅延速報EX
</Text>
<View style={{ flex: 1 }} />
<Text style={{ fontSize: 30, fontWeight: "bold", color: "white" }}>
{getTime
? getTime.toLocaleTimeString("ja-JP").split(":")[0] +
":" +
getTime.toLocaleTimeString("ja-JP").split(":")[1]
: NaN}
</Text>
<Ionicons
name="reload"
color="white"
size={30}
style={{ margin: 5 }}
onPress={() => {
LayoutAnimation.easeInEaseOut();
setLoadingDelayData(true);
}}
/>
</View>
<View style={styles.box}>
{loadingDelayData ? (
<View style={{ alignItems: "center" }}>
<LottieView
autoPlay
loop
style={{ width: 150, height: 150, backgroundColor: "#fff" }}
source={require("./assets/51690-loading-diamonds.json")}
/>
</View>
) : delayData ? (
delayData.map((d, index) => {
let data = d.split(" ");
return (
<View style={{ flexDirection: "row" }} key={data[1] + "key"}>
<Text style={{ flex: 15, fontSize: 20 }}>
{data[0].replace("\n", "")}
</Text>
<Text style={{ flex: 5, fontSize: 20 }}>{data[1]}</Text>
<Text style={{ flex: 6, fontSize: 20 }}>{data[3]}</Text>
</View>
);
})
) : (
<Text>現在5分以上の遅れはありません</Text>
)}
</View>
</ScrollView>
<View style={styles.bottom}>
<View style={{ flex: 1 }} />
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
詳細を見る
</Text>
<View style={{ flex: 1 }} />
</View>
</TouchableOpacity>
);
};