diff --git a/expo/Screens.tsx b/expo/Screens.tsx index 1aca7948..b3af319a 100644 --- a/expo/Screens.tsx +++ b/expo/Screens.tsx @@ -5,7 +5,7 @@ import S1 from './features/feed/FeedItemScreen'; import S2 from './features/home/HomeScreen'; import S3 from './features/settings/theme/ThemeColorSelectorScreen'; import S4 from './features/settings/theme/ThemeSettingsScreen'; -import S5 from './features/upfc/UPFCSettingsScreen'; +import S5 from './features/upfc/settings/UPFCSettingsScreen'; const Screens = [ S0, diff --git a/expo/assets/translations.json b/expo/assets/translations.json index cf2d69f3..82cab214 100644 --- a/expo/assets/translations.json +++ b/expo/assets/translations.json @@ -51,6 +51,24 @@ "FC Settings": { "ja": "ファンクラブ設定" }, + "FC Member Number": { + "ja": "FC会員番号" + }, + "FC Password": { + "ja": "FCパスワード" + }, + "Sync Events to Calendar": { + "ja": "カレンダーにイベントを同期する" + }, + "Event Prefix": { + "ja": "イベントのプレフィックス" + }, + "Save": { + "ja": "保存" + }, + "Clear": { + "ja": "クリア" + }, "Logout": { "ja": "ログアウト" } diff --git a/expo/features/common/components/form/CalendarDropdown.tsx b/expo/features/common/components/form/CalendarDropdown.tsx new file mode 100644 index 00000000..60f5a6c7 --- /dev/null +++ b/expo/features/common/components/form/CalendarDropdown.tsx @@ -0,0 +1,97 @@ +import { useEffect, useMemo, useState } from "react"; +import { Platform } from "react-native"; +import * as Calendar from "expo-calendar"; +import Dropdown from "@hpapp/features/common/components/form/Dropdown"; + +const NULL_CALENDER_VALUE = "__CALENDER_IS_NULL__"; + +export type CalendarDropdownProps = { + renderIfPermissionDenied: React.ReactElement; + onSelect: (calender: Calendar.Calendar | null) => void; + includeNull?: boolean; + nullText?: string; +} & Omit, "onValueChange" | "items">; + +// CalenderDropdown provides a Dropdown component for calendars defined in users Operating System. +export default function CalendarDropdown({ + renderIfPermissionDenied, + includeNull, + nullText, + onSelect, + selectedValue, +}: CalendarDropdownProps) { + const [isRequestingPermission, setIsRequsetingPermission] = + useState(true); + const [calendars, setCalendars] = useState([]); + useEffect(() => { + (async () => { + let reminderGranted = true; + const { granted } = await Calendar.requestCalendarPermissionsAsync(); + if (Platform.OS === "ios") { + const { granted } = await Calendar.requestRemindersPermissionsAsync(); + reminderGranted = granted; + } + if (granted && reminderGranted) { + const calendars = await Calendar.getCalendarsAsync( + Calendar.EntityTypes.EVENT + ); + // for Android, getEventsAsync return nothing if the calender is not visible so + // users have to select from only visible calendars. + if (Platform.OS === "android") { + setCalendars( + calendars.filter( + (c) => c.isVisible === true && c.allowsModifications + ) + ); + } else { + setCalendars(calendars.filter((c) => c.allowsModifications)); + } + setIsRequsetingPermission(false); + } + })(); + }, []); + const items = useMemo(() => { + const calendarItems = calendars.map((c) => { + return { + key: c.id, + label: c.title, + value: c.id, + }; + }); + + if (nullText) { + return [ + { + key: "null", + label: nullText, + value: NULL_CALENDER_VALUE, + }, + ].concat(calendarItems); + } + return calendarItems; + }, [calendars]); + if (isRequestingPermission) { + return null; + } + if (calendars.length == 0) { + return renderIfPermissionDenied; + } + return ( + { + if (itemValue === NULL_CALENDER_VALUE) { + onSelect(null); + } else { + for (let i = 0; i < calendars.length; i++) { + if (calendars[i].id === itemValue) { + onSelect(calendars[i]); + return; + } + } + } + }} + /> + ); +} diff --git a/expo/features/common/components/form/Dropdown.tsx b/expo/features/common/components/form/Dropdown.tsx new file mode 100644 index 00000000..3acd015f --- /dev/null +++ b/expo/features/common/components/form/Dropdown.tsx @@ -0,0 +1,79 @@ +import React, { useCallback } from "react"; +import { View, StyleSheet, ActionSheetIOS } from "react-native"; +import { Icon, Input } from "@rneui/themed"; +import { Picker } from "@react-native-picker/picker"; +import { Platform } from "react-native"; +import { IconSize, Spacing } from "@hpapp/features/common/constants"; + +type DropdownItem = { + key?: string; + label: string; + value: string; +}; + +type DropdownProps = { + selectedValue: string | undefined; + onValueChange: (value: string) => void; + items: Array; +}; + +function DropdownAndroid({ + selectedValue, + onValueChange, + items, +}: DropdownProps) { + return ( + + {items.map((c) => { + return ( + + ); + })} + + ); +} + +const iOSStyles = StyleSheet.create({ + icon: { + position: "absolute", + top: 28, + right: 10, + }, +}); + +function DropdownIOS({ selectedValue, onValueChange, items }: DropdownProps) { + const onPress = useCallback(() => { + ActionSheetIOS.showActionSheetWithOptions( + { + options: items.map((i) => i.label), + }, + (buttonIndex) => { + onValueChange(items[buttonIndex].value); + } + ); + }, [onValueChange, items]); + + const selected = items.filter((i) => i.value === selectedValue); + const valueText = selected.length > 0 ? selected[0].label : items[0].label; + return ( + <> + + + + + + ); +} + +const Dropdown = Platform.OS === "ios" ? DropdownIOS : DropdownAndroid; + +export default Dropdown; diff --git a/expo/features/root/index.tsx b/expo/features/root/index.tsx index fe350b09..8c12839a 100644 --- a/expo/features/root/index.tsx +++ b/expo/features/root/index.tsx @@ -11,13 +11,18 @@ import ProtectedRoot from "@hpapp/features/root/protected/ProtectedRoot"; import GuestRoot from "@hpapp/features/root/GuestRoot"; import { ScreenList } from "@hpapp/features/root/protected/stack"; import { LocalUserConfigurationSettings } from "@hpapp/contexts/settings/useLocalUserConfig"; +import { UPFCSettings } from "@hpapp/features/upfc/settings/UPFCSettings"; import { useFonts, BIZUDGothic_400Regular, BIZUDGothic_700Bold, } from "@expo-google-fonts/biz-udgothic"; -const settings = [CurrentUserSettings, LocalUserConfigurationSettings]; +const settings = [ + CurrentUserSettings, + LocalUserConfigurationSettings, + UPFCSettings, +]; function UserRoot({ LoginContainer, diff --git a/expo/features/settings/SettingsTab.tsx b/expo/features/settings/SettingsTab.tsx index 7254d9cc..5d3a50bf 100644 --- a/expo/features/settings/SettingsTab.tsx +++ b/expo/features/settings/SettingsTab.tsx @@ -7,7 +7,7 @@ import { ListItem } from "@rneui/base"; import { t } from "@hpapp/system/i18n"; import LogoutListItem from "@hpapp/features/settings/LogoutListItem"; import VersionSignature from "@hpapp/features/settings/VersionSignature"; -import UPFCSettingsScreen from "@hpapp/features/upfc/UPFCSettingsScreen"; +import UPFCSettingsScreen from "@hpapp/features/upfc/settings/UPFCSettingsScreen"; export default function SettingsTab() { return ( diff --git a/expo/features/upfc/scraper/DemoScraper.ts b/expo/features/upfc/scraper/DemoScraper.ts new file mode 100644 index 00000000..383cac9d --- /dev/null +++ b/expo/features/upfc/scraper/DemoScraper.ts @@ -0,0 +1,240 @@ +import { getToday, N_DAYS, N_HOURS } from "@hpapp/foundation/date"; +import { EventApplicationTickets, Scraper } from "./types"; + +const TODAY = getToday().getTime(); +const DemoData: EventApplicationTickets[] = [ + { + name: "譜久村聖30thバースデーイベント", + tickets: [ + { + venue: "日本武道館", + openAt: new Date("2026-10-30T17:00:00"), + startAt: new Date("2026-10-30T18:00:00"), + status: "申込済", + num: 1, + }, + { + venue: "日本武道館", + startAt: new Date("2026-10-30T19:00:00"), + openAt: new Date("2026-10-30T20:00:00"), + status: "申込済", + num: 1, + }, + ], + }, + { + name: "横山玲奈30thバースデーイベント", + tickets: [ + { + venue: "日本武道館", + openAt: new Date("2031-02-22T17:30:00"), + startAt: new Date("2031-02-22T18:00:00"), + status: "入金済", + num: 1, + }, + { + venue: "日本武道館", + openAt: new Date("2031-02-22T19:30:00"), + startAt: new Date("2031-02-22T20:00:00"), + status: "落選", + num: 1, + }, + ], + }, + { + name: "野中美希30thバースデーイベント", + tickets: [ + { + venue: "日本武道館", + openAt: new Date("2029-10-07T17:30:00"), + startAt: new Date("2029-10-07T18:00:00"), + status: "入金待", + num: 1, + }, + { + venue: "日本武道館", + openAt: new Date("2029-10-07T19:30:00"), + startAt: new Date("2029-10-07T20:00:00"), + status: "入金待", + num: 1, + }, + ], + }, + // past event with 入金待 status (should be render as '入金忘') + { + name: "譜久村聖20thバースデーイベント", + tickets: [ + { + venue: "日本武道館", + openAt: new Date("2016-10-07T17:30:00"), + startAt: new Date("2016-10-07T18:00:00"), + status: "入金待", + num: 1, + }, + { + venue: "日本武道館", + openAt: new Date("2016-10-07T19:30:00"), + startAt: new Date("2016-10-07T20:00:00"), + status: "入金待", + num: 1, + }, + ], + }, + + // tickets with event metadata introduced by https:--github.com-yssk22-sites-issues-429 + // 1. Event Payment Due Date is Today + { + name: "山﨑愛生30thバースデーイベント", + applicationStartDate: new Date(TODAY - 14 * N_DAYS), + applicationDueDate: new Date(TODAY - 7 * N_DAYS), + paymentOpenDate: new Date(TODAY - 3 * N_DAYS), + paymentDueDate: new Date(TODAY), + tickets: [ + { + venue: "日本武道館", + openAt: new Date("2035-06-30T17:00:00"), + startAt: new Date("2035-06-30T18:00:00"), + status: "入金待", + num: 1, + }, + { + venue: "日本武道館", + startAt: new Date("2026-06-30T19:00:00"), + openAt: new Date("2026-06-30T20:00:00"), + status: "入金待", + num: 1, + }, + ], + }, + // 2. Event Payment Due Date is past + { + name: "山﨑夢羽30thバースデーイベント", + applicationStartDate: new Date(TODAY - 14 * N_DAYS), + applicationDueDate: new Date(TODAY - 7 * N_DAYS), + paymentOpenDate: new Date(TODAY - 5 * N_DAYS), + paymentDueDate: new Date(TODAY - 2 * N_DAYS), + tickets: [ + { + venue: "日本武道館", + openAt: new Date("2022-11-05T17:00:00"), + startAt: new Date("2022-11-05T18:00:00"), + status: "入金待", + num: 1, + }, + { + venue: "日本武道館", + startAt: new Date("2022-11-30T19:00:00"), + openAt: new Date("2022-11-30T20:00:00"), + status: "入金待", + num: 1, + }, + ], + }, + // 3. PaymentOpenDate is future + { + name: "小田さくら30thバースデーイベント", + applicationStartDate: new Date(TODAY - 14 * N_DAYS), + applicationDueDate: new Date(TODAY - 7 * N_DAYS), + paymentOpenDate: new Date(TODAY + 2 * N_DAYS), + paymentDueDate: new Date(TODAY + 6 * N_DAYS), + tickets: [ + { + venue: "日本武道館", + openAt: new Date("2029-03-12T17:00:00"), + startAt: new Date("2029-03-12T18:00:00"), + status: "申込済", + num: 1, + }, + { + venue: "日本武道館", + startAt: new Date("2029-03-12T19:00:00"), + openAt: new Date("2029-03-12T20:00:00"), + status: "申込済", + num: 1, + }, + ], + }, + // for display only, comming soon events + { + name: "今週のイベントサンプル", + applicationStartDate: new Date(TODAY - 14 * N_DAYS), + applicationDueDate: new Date(TODAY - 7 * N_DAYS), + paymentOpenDate: new Date(TODAY - 2 * N_DAYS), + paymentDueDate: new Date(TODAY - 1 * N_DAYS), + tickets: [ + { + venue: "埼玉県川口総合文化センター・リリア メインホール", + openAt: new Date(TODAY + 1 * N_DAYS + 14 * N_HOURS), + startAt: new Date(TODAY + 1 * N_DAYS + 15 * N_HOURS), + status: "入金済", + num: 1, + }, + { + venue: "埼玉県川口総合文化センター・リリア メインホール", + openAt: new Date(TODAY + 2 * N_DAYS + 14 * N_HOURS), + startAt: new Date(TODAY + 2 * N_DAYS + 15 * N_HOURS), + status: "入金済", + num: 1, + }, + ], + }, + { + // looooong name + // eslint-disable-next-line quotes + name: "モーニング娘。'21 10期メンバー 石田亜佑美&佐藤優樹FCイベント~ひよこが10年経ったら、さぁ何になる?~『まーバースデーやってないよ。せめて衣装だけ着させて!』『いや、タイトル長いよ!』 ", + applicationStartDate: new Date(TODAY - 14 * N_DAYS), + applicationDueDate: new Date(TODAY - 7 * N_DAYS), + paymentOpenDate: new Date(TODAY - 1 * N_DAYS), + paymentDueDate: new Date(TODAY + 7 * N_DAYS), + tickets: [ + { + venue: "東京駅", + openAt: new Date(TODAY + 30 * N_DAYS + 18 * N_HOURS), + startAt: new Date(TODAY + 30 * N_DAYS + 19 * N_HOURS), + status: "入金待", + num: 1, + }, + { + venue: "日本武道館", + openAt: new Date(TODAY + 30 * N_DAYS + 15 * N_HOURS), + startAt: new Date(TODAY + 30 * N_DAYS + 16 * N_HOURS), + status: "入金待", + num: 1, + }, + ], + }, + // Open Event with due date + { + name: "入江里咲30thバースデーイベント", + applicationStartDate: new Date(TODAY - 14 * N_DAYS), + applicationDueDate: new Date(TODAY - 7 * N_DAYS), + paymentOpenDate: new Date(TODAY - 5 * N_DAYS), + paymentDueDate: new Date(TODAY - 2 * N_DAYS), + tickets: [], + }, + // Open Event without due date + { + name: "譜久村聖40thバースデーイベント", + tickets: [], + }, +]; + +export default class DummyScraper implements Scraper { + static Username = "00000000"; + // eslint-disable-next-line @typescript-eslint-no-unused-vars + async authenticate(username: string, _: string): Promise { + return new Promise((resolve) => { + setTimeout(() => { + resolve(username === DummyScraper.Username); + }, 1000); + }); + } + + async getEventApplications(): Promise { + return new Promise((resolve) => { + setTimeout(() => { + resolve(DemoData); + }, 500); + }); + } +} diff --git a/expo/features/upfc/scraper/FileFetcher.ts b/expo/features/upfc/scraper/FileFetcher.ts new file mode 100644 index 00000000..f73ff9b7 --- /dev/null +++ b/expo/features/upfc/scraper/FileFetcher.ts @@ -0,0 +1,46 @@ +import { readFile } from "@hpapp/foundation/test_helper"; + +export default class FileFetcher { + private username: string; + private password: string; + private paths: { + redirectPageHtmlPath: string; + openEventApplicationsHtmlPath: string; + openExecEventApplicationsHtmlPath: string; + ticketsHtmlPath: string; + }; + + constructor( + username: string, + password: string, + paths: { + redirectPageHtmlPath: string; + openEventApplicationsHtmlPath: string; + openExecEventApplicationsHtmlPath: string; + ticketsHtmlPath: string; + } + ) { + this.username = username; + this.password = password; + this.paths = paths; + } + + async postCredential(username: string, password: string): Promise { + if (username != this.username || password != this.password) { + return ""; + } + return await readFile(this.paths.redirectPageHtmlPath); + } + + async fetchEventApplicationsHtml(): Promise { + return await readFile(this.paths.openEventApplicationsHtmlPath); + } + + async fetchExecEventApplicationsHtml(): Promise { + return await readFile(this.paths.openExecEventApplicationsHtmlPath); + } + + async fetchTicketsHtml(): Promise { + return await readFile(this.paths.ticketsHtmlPath); + } +} diff --git a/expo/features/upfc/scraper/UPFCScraper.test.ts b/expo/features/upfc/scraper/UPFCScraper.test.ts new file mode 100644 index 00000000..fbb0c93f --- /dev/null +++ b/expo/features/upfc/scraper/UPFCScraper.test.ts @@ -0,0 +1,229 @@ +import * as path from "path"; +import UPFCScraper from "./UPFCScraper"; +import FileFetcher from "./FileFetcher"; +import { + ErrAuthentication, + EventApplicationTickets, +} from "@hpapp/features/upfc/scraper/types"; +import { readFileAsJSON } from "@hpapp/foundation/test_helper"; + +describe("Scraper", () => { + describe("authorize", () => { + it("should return true if valid redirection page is responded", async () => { + const fetcher = new FileFetcher("mizuki", "fukumura", { + redirectPageHtmlPath: path.join( + __dirname, + "./testdata/valid-redirect.html" + ), + openEventApplicationsHtmlPath: path.join( + __dirname, + "./testdata/valid-available-applications.html" + ), + openExecEventApplicationsHtmlPath: path.join( + __dirname, + "./testdata/valid-available-applications-exe.html" + ), + ticketsHtmlPath: path.join( + __dirname, + "./testdata/valid-tickets-page.html" + ), + }); + const scraper = new UPFCScraper(fetcher); + const result = await scraper.authenticate("mizuki", "fukumura"); + expect(result).toBe(true); + }); + + it("should throw ErrAuthentication if wrong redirection page is responded", async () => { + const fetcher = new FileFetcher("mizuki", "fukumura", { + redirectPageHtmlPath: path.join( + __dirname, + "./testdata/valid-no-events.html" + ), + openEventApplicationsHtmlPath: path.join( + __dirname, + "./testdata/valid-available-applications.html" + ), + openExecEventApplicationsHtmlPath: path.join( + __dirname, + "./testdata/valid-available-applications-exe.html" + ), + ticketsHtmlPath: path.join( + __dirname, + "./testdata/valid-tickets-page.html" + ), + }); + const scraper = new UPFCScraper(fetcher); + expect.assertions(1); + return scraper + .authenticate("mizuki", "fukumura") + .catch((e) => expect(e).toBe(ErrAuthentication)); + }); + }); + + describe("getEventApplications", () => { + it("should return all Applications in tickets page", async () => { + const fetcher = new FileFetcher("mizuki", "fukumura", { + redirectPageHtmlPath: path.join( + __dirname, + "./testdata/valid-redirect.html" + ), + openEventApplicationsHtmlPath: "", + openExecEventApplicationsHtmlPath: "", + ticketsHtmlPath: path.join( + __dirname, + "./testdata/valid-tickets-page.html" + ), + }); + const scraper = new UPFCScraper(fetcher); + const got = await scraper.getEventApplications(); + const expected = await readFileAsJSON>( + path.join(__dirname, "./testdata/valid-tickets-page.expected.json") + ); + expect(got.length).toBe(expected.length); + expected.forEach((e, i) => { + const g = got[i]; + expect(g.name).toBe(e.name); + expect(g.applicationID).toBe(undefined); // ticket page shouldn't have applicationID + expect(g.tickets.length).toBe(e.tickets.length); + e.tickets.forEach((et, i) => { + const gt = g.tickets[i]; + expect(gt.num).toBe(et.num); + expect(gt.venue).toBe(et.venue); + expect(gt.openAt!.getTime()).toBe(new Date(et.openAt!).getTime()); + expect(gt.startAt.getTime()).toBe(new Date(et.startAt).getTime()); + expect(gt.status).toBe(et.status); + }); + }); + }); + }); + + describe("getEventApplications", () => { + it("should return all Applications in applications page", async () => { + const fetcher = new FileFetcher("mizuki", "fukumura", { + redirectPageHtmlPath: path.join( + __dirname, + "./testdata/valid-redirect.html" + ), + openEventApplicationsHtmlPath: path.join( + __dirname, + "./testdata/valid-available-applications.html" + ), + openExecEventApplicationsHtmlPath: "", + ticketsHtmlPath: path.join(__dirname, "./testdata/test-no-event.html"), + }); + const scraper = new UPFCScraper(fetcher); + const got = await scraper.getEventApplications(); + const expected = await readFileAsJSON>( + path.join( + __dirname, + "./testdata/valid-available-applications.expected.json" + ) + ); + expect(got.length).toBe(expected.length); + expected.forEach((e, i) => { + const g = got[i]; + expect(g.name).toBe(e.name); + expect(g.applicationID).toBe(e.applicationID); + expect(g.applicationStartDate!.getTime()).toBe( + new Date(e.applicationStartDate!).getTime() + ); + expect(g.applicationDueDate!.getTime()).toBe( + new Date(e.applicationDueDate!).getTime() + ); + expect(g.paymentOpenDate!.getTime()).toBe( + new Date(e.paymentOpenDate!).getTime() + ); + expect(g.paymentDueDate!.getTime()).toBe( + new Date(e.paymentDueDate!).getTime() + ); + }); + }); + + it("should return all Applications in applications page (exe)", async () => { + const fetcher = new FileFetcher("mizuki", "fukumura", { + redirectPageHtmlPath: path.join( + __dirname, + "./testdata/valid-redirect.html" + ), + openEventApplicationsHtmlPath: "", + openExecEventApplicationsHtmlPath: path.join( + __dirname, + "./testdata/valid-available-applications-exe.html" + ), + ticketsHtmlPath: path.join(__dirname, "./testdata/test-no-event.html"), + }); + const scraper = new UPFCScraper(fetcher); + const got = await scraper.getEventApplications(); + const expected = await readFileAsJSON>( + path.join( + __dirname, + "./testdata/valid-available-applications-exe.expected.json" + ) + ); + expect(got.length).toBe(expected.length); + expected.forEach((e, i) => { + const g = got[i]; + expect(g.name).toBe(e.name); + expect(g.applicationID).toBe(e.applicationID); + expect(g.applicationStartDate!.getTime()).toBe( + new Date(e.applicationStartDate!).getTime() + ); + expect(g.applicationDueDate!.getTime()).toBe( + new Date(e.applicationDueDate!).getTime() + ); + expect(g.paymentOpenDate!.getTime()).toBe( + new Date(e.paymentOpenDate!).getTime() + ); + expect(g.paymentDueDate!.getTime()).toBe( + new Date(e.paymentDueDate!).getTime() + ); + }); + }); + it("should return all Applications listed in tickets, applications, and exe applications", async () => { + const fetcher = new FileFetcher("mizuki", "fukumura", { + redirectPageHtmlPath: path.join( + __dirname, + "./testdata/valid-redirect.html" + ), + openEventApplicationsHtmlPath: path.join( + __dirname, + "./testdata/integration-test-available-applications.html" + ), + openExecEventApplicationsHtmlPath: path.join( + __dirname, + "./testdata/integration-test-available-applications-exe.html" + ), + ticketsHtmlPath: path.join( + __dirname, + "./testdata/integration-test-tickets.html" + ), + }); + const scraper = new UPFCScraper(fetcher); + const got = await scraper.getEventApplications(); + const expected = await readFileAsJSON>( + path.join(__dirname, "./testdata/integration-test.exepected.json") + ); + + expect(got.length).toBe(expected.length); + expected.forEach((e, i) => { + const g = got[i]; + expect(g.name).toBe(e.name); + expect(g.applicationID).toBe(e.applicationID); + if (g.applicationStartDate !== undefined) { + expect(g.applicationStartDate!.getTime()).toBe( + new Date(e.applicationStartDate!).getTime() + ); + expect(g.applicationDueDate!.getTime()).toBe( + new Date(e.applicationDueDate!).getTime() + ); + expect(g.paymentOpenDate!.getTime()).toBe( + new Date(e.paymentOpenDate!).getTime() + ); + expect(g.paymentDueDate!.getTime()).toBe( + new Date(e.paymentDueDate!).getTime() + ); + } + }); + }); + }); +}); diff --git a/expo/features/upfc/scraper/UPFCScraper.ts b/expo/features/upfc/scraper/UPFCScraper.ts new file mode 100644 index 00000000..2ade1d33 --- /dev/null +++ b/expo/features/upfc/scraper/UPFCScraper.ts @@ -0,0 +1,325 @@ +import * as date from "@hpapp/foundation/date"; +import { Scraper } from "./types"; +import { + ErrAuthentication, + EventApplication, + EventApplicationTickets, + EventDateTime, + Fetcher, + TicketStatus, +} from "./types"; + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const jsdom = require("jsdom-jscore-rn").jsdom; + +export default class UPFCScraper implements Scraper { + private readonly fetcher: Fetcher; + + constructor(fetcher: Fetcher) { + this.fetcher = fetcher; + } + + async authenticate(username: string, password: string): Promise { + const html = await this.fetcher.postCredential(username, password); + if (!this.parseRedirectPageHTML(html)) { + throw ErrAuthentication; + } + return true; + } + + async getEventApplications(): Promise { + const events = this.fetcher.fetchEventApplicationsHtml(); + const exeEvents = this.fetcher.fetchExecEventApplicationsHtml(); + const tickets = this.fetcher.fetchTicketsHtml(); + const [eventsHtml, execEventHtml, ticketsHtml] = await Promise.all([ + events, + exeEvents, + tickets, + ]); + return this.parseEventApplications(eventsHtml, execEventHtml, ticketsHtml); + } + + parseRedirectPageHTML(text: string) { + const doc = jsdom(text); + const meta = doc.getElementsByTagName("meta"); + for (let i = 0; i < meta.length; i++) { + const equiv = meta[i].getAttribute("http-equiv") as string | null; + if (equiv && equiv.toLowerCase() === "refresh") { + const content = meta[i].getAttribute("content") as string | null; + // eslint-disable-next-line quotes + if (content && content.toLowerCase() === "0;url='index.php'") { + return true; + } + } + } + return false; + } + + parseEventApplications( + eventsHtml: string, + execEventHtml: string, + ticketsHtml: string + ): EventApplicationTickets[] { + const eventApplications = this.parseEventApplicationsHtml(eventsHtml); + const execEventApplications = + this.parseEventApplicationsHtml(execEventHtml); + const ticketApplications = this.parseTicketsHtml(ticketsHtml); + const result: EventApplicationTickets[] = []; + const eventMap: Map = new Map(); + const allApplications = eventApplications.concat(execEventApplications); + for (const i in allApplications) { + const a = allApplications[i]; + if (!eventMap.has(a.name)) { + const eat = { + ...a, + tickets: [], + }; + eventMap.set(eat.name, eat); + result.push(eat); + } + } + for (const i in ticketApplications) { + const eat = ticketApplications[i]; + if (eventMap.has(eat.name)) { + const existing = eventMap.get(eat.name)!; + const { tickets } = eat; + existing.tickets = existing.tickets.concat(tickets); + } else { + // past ticket where the application is no longer available + result.push(eat); + eventMap.set(eat.name, eat); + } + } + return result; + } + + parseEventApplicationsHtml(text: string): EventApplication[] { + const doc = jsdom(text); + const links = doc.querySelectorAll("div.contents-body a"); + if (links === null) { + throw new Error("unexpected dom"); + } + const applications: EventApplication[] = []; + for (let i = 0; i < links.length; i++) { + const availalble = this.parseEventApplicationLink(links[i]); + if (availalble) { + applications.push(availalble); + } + } + return applications; + } + + parseTicketsHtml(text: string): EventApplicationTickets[] { + const doc = jsdom(text); + const today = date.getToday(); + const content = doc.querySelector("div.mypage_contents"); + if (content === null) { + return []; + } + const allApplications: Array = []; + const eventNameDOMs = content.querySelectorAll("dt"); + const eventAttrDOMs = content.querySelectorAll("dd"); + + for (let i = 0; i < eventNameDOMs.length; i++) { + const node = eventNameDOMs.item(i); + const application: EventApplicationTickets = { + name: this.parseEventApplicationName(node.innerHTML.trim()), + tickets: [], + }; + const rows = eventAttrDOMs.item(i).querySelectorAll("table tr"); + for (let j = 0; j < rows.length; j++) { + const r = rows[j]; + const cols = r.querySelectorAll("td"); + if (cols.length === 7) { + const eventDate = this.parseEventDate( + cols.item(0).innerHTML, + cols.item(2).innerHTML.trim() + ); + const venue = cols + .item(1) + .innerHTML.replace("
", "") + .split("\n") + .map((s: string) => s.trim()) + .join(" ") + .trim(); + const num = this.parseNumTickets(cols.item(3).innerHTML.trim()); + let status = this.parseTicketStatus(cols.item(4).innerHTML.trim()); + if (cols.item(5).innerHTML.trim().indexOf("入金日") > 0) { + status = "入金済"; + } + if (status === "入金待") { + if (!application.paymentDueDate) { + if ( + eventDate !== null && + today.getTime() >= eventDate.startAt.getTime() + ) { + status = "入金忘"; + } + } else { + if (today.getTime() > application.paymentDueDate.getTime()) { + status = "入金忘"; + } + } + } + if (eventDate !== null) { + application.tickets.push({ + venue: venue, + openAt: eventDate.openAt, + startAt: eventDate.startAt, + status: status, + num: num, + }); + } + } + } + if (application.tickets.length > 0) { + allApplications.push(application); + } + } + return allApplications; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + parseEventApplicationLink(link: any): EventApplication | null { + const href = link.getAttribute("href"); + const titleSpan = link.querySelector("span"); + if (!href || !titleSpan) { + return null; + } + if ( + href.match(/event_Event_Announce\.php/) === null && + href.match(/fanticket_Tour_List\.php/) === null + ) { + // not an event nor exe event. + return null; + } + let match = href.match(/EventSet_ID\=(\d+)/); + let applicationID = match ? `ES_${match[1]}` : null; + if (applicationID === null) { + match = href.match(/DM_ID\=(\d+)/); + applicationID = match ? `DM_${match[1]}` : null; + } + + const span = link.querySelector("span"); + if (!span) { + return null; + } + const name = this.parseEventApplicationName( + span.textContent.trim() as string + ); + const spans = link.parentNode.children; + let dateText = null; + for (let j = 0; j < spans.length; j++) { + const span = spans[j]; + if (span.textContent.indexOf("受付期間") >= 0) { + dateText = span.textContent.trim(); + break; + } + } + if (dateText === null) { + return null; + } + const dates = this.parseEventApplicationDatesText(dateText); + if (dates == null) { + return null; + } + return { + name, + applicationID, + ...dates, + }; + } + + private parseEventApplicationName(valueStr: string) { + return valueStr.replace("■", "").trim(); + } + + private parseNumTickets(valueStr: string): number { + if (valueStr.match(/(\d+)\s*枚/)) { + return parseInt(RegExp.$1); + } + return 0; + } + + private parseTicketStatus(valueStr: string): TicketStatus { + if (valueStr.indexOf("申込済") >= 0) { + return "申込済"; + } + if (valueStr.indexOf("落選") >= 0) { + return "落選"; + } + if (valueStr.indexOf("当選") >= 0) { + if (valueStr.indexOf("入金済") >= 0) { + return "入金済"; + } + return "入金待"; + } + return "不明"; + } + + private parseEventApplicationDatesText(text: string) { + let applicationDates: [Date, Date] | null = null; + let paymentDates: [Date, Date] | null = null; + const lines = text.split("\n"); + for (let i = 0; i < lines.length; i++) { + const line = lines[i].trim(); + if (line.indexOf("受付期間") >= 0) { + applicationDates = this.extractJPDates(line); + } else if (line.indexOf("当落発表期間") >= 0) { + paymentDates = this.extractJPDates(line); + } + } + if (!applicationDates || !paymentDates) { + return null; + } + return { + applicationStartDate: applicationDates[0], + applicationDueDate: applicationDates[1], + paymentOpenDate: paymentDates[0], + paymentDueDate: paymentDates[1], + }; + } + + private parseEventDate( + dateStr: string, + timeStr: string + ): EventDateTime | null { + dateStr = dateStr.trim(); + if (dateStr.match(/(\d{4}\/\d{2}\s*\/\d{2})/)) { + dateStr = RegExp.$1.toString().replace(" ", "").replace(/\//g, "-"); + const m = timeStr.match(/(\d{2}:\d{2})/g); + if (m !== null) { + timeStr = RegExp.$1; + if (m.length > 1) { + return { + openAt: new Date(dateStr + "T" + m[0] + ":00+09:00"), + startAt: new Date(dateStr + "T" + m[1] + ":00+09:00"), + }; + } + return { + startAt: new Date(dateStr + "T" + m[0] + ":00+09:00"), + }; + } + } + return null; + } + private static jpDateRegexp = /\s*\d{4}\s*年\s*\d{2}\s*月\s*\d{2}\s*日/g; + + private extractJPDates(text: string): [Date, Date] | null { + const matches = text.match(UPFCScraper.jpDateRegexp); + const dates = matches?.map((m) => { + const dateStr = m + .replace(/\s*/g, "") + .replace("年", "-") + .replace("月", "-") + .replace("日", ""); + return new Date(dateStr + "T00:00:00+09:00"); + }); + if (dates?.length != 2) { + return null; + } + return [dates[0], dates[1]]; + } +} + +export { UPFCScraper }; diff --git a/expo/features/upfc/scraper/URLFetcher.ts b/expo/features/upfc/scraper/URLFetcher.ts new file mode 100644 index 00000000..3985309f --- /dev/null +++ b/expo/features/upfc/scraper/URLFetcher.ts @@ -0,0 +1,49 @@ +import { ErrInvalidStatusCode } from './types'; + +export default class URLFetcher { + async postCredential(username: string, password: string): Promise { + const url = 'https://www.up-fc.jp/helloproject/fanclub_Login.php'; + await this.fetch(url); // dummy request to generate session + + const params = new URLSearchParams(); + params.append('User_No', username); + params.append('User_LoginPassword', password); + params.append('pp', 'OK'); + params.append('@Control_Name@', '認証'); + const resp = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', + }, + body: params.toString(), + credentials: 'include', + }); + if (!resp.ok) { + throw ErrInvalidStatusCode; + } + return await resp.text(); + } + + async fetchEventApplicationsHtml(): Promise { + return await this.fetch('https://www.up-fc.jp/helloproject/event_Event_SetList.php'); + } + + async fetchExecEventApplicationsHtml(): Promise { + return await this.fetch('https://www.up-fc.jp/helloproject/fanticket_DM_List.php'); + } + + async fetchTicketsHtml(): Promise { + return await this.fetch('https://www.up-fc.jp/helloproject/mypage02.php'); + } + + async fetch(url: string): Promise { + const resp = await fetch(url, { + credentials: 'include', + }); + if (!resp.ok) { + throw ErrInvalidStatusCode; + } + const html = await resp.text(); + return html; + } +} diff --git a/expo/features/upfc/scraper/hooks.tsx b/expo/features/upfc/scraper/hooks.tsx new file mode 100644 index 00000000..5a4adf93 --- /dev/null +++ b/expo/features/upfc/scraper/hooks.tsx @@ -0,0 +1,16 @@ +import { Scraper } from './types'; +import DemoScraper from './DemoScraper'; +import UPFCScraper from './UPFCScraper'; +import URLFetcher from './URLFetcher'; + +const scraper = new UPFCScraper(new URLFetcher()); +const demoScraper = new DemoScraper(); + +const useScraper = (useDemo: boolean): Scraper => { + if (useDemo) { + return demoScraper; + } + return scraper; +}; + +export { useScraper }; diff --git a/expo/features/upfc/scraper/index.ts b/expo/features/upfc/scraper/index.ts new file mode 100644 index 00000000..64c4792d --- /dev/null +++ b/expo/features/upfc/scraper/index.ts @@ -0,0 +1,5 @@ +export * from './types'; +export * from './hooks'; + +import DemoScraper from './DemoScraper'; +export { DemoScraper }; diff --git a/expo/features/upfc/scraper/testdata/integration-test-available-applications-exe.html b/expo/features/upfc/scraper/testdata/integration-test-available-applications-exe.html new file mode 100644 index 00000000..bf640aba --- /dev/null +++ b/expo/features/upfc/scraper/testdata/integration-test-available-applications-exe.html @@ -0,0 +1,215 @@ + + + + + + + + + +Hello! Project + + + + +
+ +
+ + +
+ +
+ + +
+ +

チケット/イベント受付(先々行受付)

+
+ +
+ + +
+
+ +
+ + + + + + + + + + + + +

チケット/イベント受付(先々行受付) 受付&確認

+
+ + アンジュルム 日本武道館 先々行 + +
+ + 受付期間  :2021年09月13日(月)17時00分~2021年09月20日(月)23時00分まで
+ 受付確認期間:2021年09月13日(月)17時00分~2021年09月20日(月)23時00分まで
+ 当落発表期間:2021年09月22日(水)16時00分~2021年09月30日(木)23時00分まで
+
+
+ ※エグゼクティブ会員限定 +
+
+
+ +
+
+
+
+ + Juice=Juice横浜アリーナ先々行 + +
+ + 受付期間  :2021年09月24日(金)17時00分~2021年09月29日(水)12時00分まで
+ 受付確認期間:2021年09月24日(金)17時00分~2021年09月29日(水)12時00分まで
+ 当落発表期間:2021年09月29日(水)17時00分~2021年10月03日(日)23時00分まで
+
+
+ ※エグゼクティブ会員限定(ご来場の際は、チケット名義人のエグゼクティブパスまたは本人確認書類をご持参ください。) +
+
+
+ +
+
+
+
+ + モーニング娘。’21 日本武道館 先々行 + +
+ + 受付期間  :2021年09月24日(金)17時00分~2021年09月29日(水)12時00分まで
+ 受付確認期間:2021年09月24日(金)17時00分~2021年09月29日(水)12時00分まで
+ 当落発表期間:2021年09月29日(水)17時00分~2021年10月03日(日)23時00分まで
+
+
+ ※エグゼクティブ会員限定(ご来場の際は、チケット名義人のエグゼクティブパスまたは本人確認書類をご持参ください。) +
+
+
+ +
+
+
+
+ +

+ +
+ +

+ +
+
+
+
+
+ + + +
+ + + + diff --git a/expo/features/upfc/scraper/testdata/integration-test-available-applications.html b/expo/features/upfc/scraper/testdata/integration-test-available-applications.html new file mode 100644 index 00000000..11231d40 --- /dev/null +++ b/expo/features/upfc/scraper/testdata/integration-test-available-applications.html @@ -0,0 +1,443 @@ + + + + + + + + + +Hello! Project + + + + + +
+ +
+ + +
+ +
+ + +
+ + +

チケット/イベント受付(先行受付)

+
+ +
+ + + +
+
+
+ + + + + + + +

【NEXT先行】鈴木愛理 LIVE 2021~26/27~ @ 大阪・名古屋 お申し込み受付

+
+ 【NEXT先行】鈴木愛理 LIVE 2021~26/27~ @ 大阪・名古屋
+ + 受付期間  :2021年09月16日(木) 16時~2021年09月22日(水) 17時まで
+ 受付確認期間:2021年09月16日(木) 16時~2021年09月22日(水) 17時まで
+ + 当落発表期間:2021年09月24日(金) 18時~2021年09月30日(木) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。
+ご当選された場合、振込用紙の発送はございません。
+抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。
+(郵便局でお支払いされた場合は返金となりますので、ご注意ください。)

+

+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

ENPLEX × Hello! Project 名古屋定期イベント「アンジュルム 竹内朱莉 ‶竹を割ったような″イベント in 名古屋」 お申し込み受付

+
+ ENPLEX × Hello! Project 名古屋定期イベント「アンジュルム 竹内朱莉 ‶竹を割ったような″イベント in 名古屋」
+ + 受付期間  :2021年09月16日(木) 17時~2021年09月28日(火) 12時まで
+ 受付確認期間:2021年09月16日(木) 17時~2021年09月28日(火) 12時まで
+ + 当落発表期間:2021年09月30日(木) 16時~2021年10月06日(水) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。ご当選された場合、振込用紙の発送はございません。抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。 + +
+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

【NEXT先行】工藤遥バースデーイベント2021 ~22nd Best day ever~きょうやすSP お申し込み受付

+
+ 【NEXT先行】工藤遥バースデーイベント2021 ~22nd Best day ever~きょうやすSP
+ + 受付期間  :2021年09月16日(木) 16時~2021年09月24日(金) 17時まで
+ 受付確認期間:2021年09月16日(木) 16時~2021年09月24日(金) 17時まで
+ + 当落発表期間:2021年09月27日(月) 16時~2021年10月03日(日) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承下さい。
+ご当選された場合、振込用紙の発送はございません。
+抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払下さい。
+(郵便局でお支払いされた場合は返金となりますので、ご注意下さい。)


+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

【NEXT先行】宮崎由加ファンクラブイベント2021~Halloween yukanya~ お申し込み受付

+
+ 【NEXT先行】宮崎由加ファンクラブイベント2021~Halloween yukanya~
+ + 受付期間  :2021年09月15日(水) 16時~2021年09月22日(水) 17時まで
+ 受付確認期間:2021年09月15日(水) 16時~2021年09月22日(水) 17時まで
+ + 当落発表期間:2021年09月24日(金) 16時~2021年09月30日(木) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承下さい。
+ご当選された場合、振込用紙の発送はございません。
+抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払下さい。
+(郵便局でお支払いされた場合は返金となりますので、ご注意下さい。)


+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

Juice=Juice新メンバー 有澤一華・入江里咲・江端妃咲FCイベント2021 お申し込み受付

+
+ Juice=Juice新メンバー 有澤一華・入江里咲・江端妃咲FCイベント2021
+ + 受付期間  :2021年09月15日(水) 18時~2021年09月29日(水) 23時まで
+ 受付確認期間:2021年09月15日(水) 18時~2021年09月29日(水) 23時まで
+ + 当落発表期間:2021年10月01日(金) 16時~2021年10月06日(水) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。ご当選された場合、振込用紙の発送はございません。抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。 +
+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

アンジュルム 上國料萌衣&笠原桃奈バースデーイベント2021 お申し込み受付

+
+ アンジュルム 上國料萌衣&笠原桃奈バースデーイベント2021
+ + 受付期間  :2021年09月14日(火) 18時~2021年09月28日(火) 12時まで
+ 受付確認期間:2021年09月14日(火) 18時~2021年09月28日(火) 12時まで
+ + 当落発表期間:2021年10月01日(金) 16時~2021年10月06日(水) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。ご当選された場合、振込用紙の発送はございません。抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。 +
+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

アンジュルム コンサート2021 「桃源郷 ~笠原桃奈 卒業スペシャル~」 お申し込み受付

+
+ アンジュルム コンサート2021 「桃源郷 ~笠原桃奈 卒業スペシャル~」
+ + 受付期間  :2021年09月13日(月) 17時~2021年09月24日(金) 17時まで
+ 受付確認期間:2021年09月13日(月) 17時~2021年09月24日(金) 17時まで
+ + 当落発表期間:2021年09月30日(木) 17時~2021年10月04日(月) 23時まで
+ +
+

+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

演劇女子部「図書館物語~3つのブックマーク~」 お申し込み受付

+
+ 演劇女子部「図書館物語~3つのブックマーク~」
+ + 受付期間  :2021年09月13日(月) 12時~2021年09月22日(水) 17時まで
+ 受付確認期間:2021年09月13日(月) 12時~2021年09月22日(水) 17時まで
+ + 当落発表期間:2021年09月28日(火) 17時~2021年10月03日(日) 23時まで
+ +
+

+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

アンジュルム 笠原桃奈バースデーイベント2021 お申し込み受付

+
+ アンジュルム 笠原桃奈バースデーイベント2021
+ + 受付期間  :2021年09月10日(金) 18時~2021年09月28日(火) 12時まで
+ 受付確認期間:2021年09月10日(金) 18時~2021年09月28日(火) 12時まで
+ + 当落発表期間:2021年09月30日(木) 16時~2021年10月06日(水) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。ご当選された場合、振込用紙の発送はございません。抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。 +
+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

BEYOOOOONDS/雨ノ森 川海 岡村美波バースデーイベント2021 お申し込み受付

+
+ BEYOOOOONDS/雨ノ森 川海 岡村美波バースデーイベント2021
+ + 受付期間  :2021年09月10日(金) 18時~2021年09月27日(月) 12時まで
+ 受付確認期間:2021年09月10日(金) 18時~2021年09月27日(月) 12時まで
+ + 当落発表期間:2021年09月29日(水) 16時~2021年10月04日(月) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。ご当選された場合、振込用紙の発送はございません。抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。 +
+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

【当日券予約】ENPLEX × Hello! Project 名古屋定期イベント「ハロプロ研修生イベント in 名古屋」 当選・落選確認

+
+ 【当日券予約】ENPLEX × Hello! Project 名古屋定期イベント「ハロプロ研修生イベント in 名古屋」
+ + 受付期間  :2021年09月09日(木) 17時~2021年09月13日(月) 17時まで
+ 受付確認期間:2021年09月09日(木) 17時~2021年09月13日(月) 17時まで
+ + 当落発表期間:2021年09月15日(水) 16時~2021年09月21日(火) 20時まで
+ +
+

+
+ 当選・落選確認
+
+
+
+
+ + + + + + + +

BEYOOOOONDS結成記念スペシャルライブ2021 ~ポップステップ付点音符.~ お申し込み受付

+
+ BEYOOOOONDS結成記念スペシャルライブ2021 ~ポップステップ付点音符.~
+ + 受付期間  :2021年09月08日(水) 18時~2021年09月23日(木) 23時まで
+ 受付確認期間:2021年09月08日(水) 18時~2021年09月23日(木) 23時まで
+ + 当落発表期間:2021年09月27日(月) 16時~2021年10月03日(日) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。ご当選された場合、振込用紙の発送はございません。抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。 +
+
+ お申し込み受付
+
+
+
+
+
+
+
+
+ + + +
+ + + + diff --git a/expo/features/upfc/scraper/testdata/integration-test-tickets.html b/expo/features/upfc/scraper/testdata/integration-test-tickets.html new file mode 100644 index 00000000..2018e2c4 --- /dev/null +++ b/expo/features/upfc/scraper/testdata/integration-test-tickets.html @@ -0,0 +1,2394 @@ + + + + + + マイページ|ハロープロジェクトオフィシャルファンクラブサイト + + + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +
+

マイページMY PAGE

+
+ + + +
※各種入金状況につきましては反映まで数日かかる場合がございます。
+ + + +
+ チケット申込状況 +
+ +
+ +
+ +
先行受付
+ + + +
+
+ ■ Juice=Juice新メンバー 有澤一華・入江里咲・江端妃咲FCイベント2021
+ +
+ + + + + + + + + + + +
+ 公演番号
+ 03 +
+ 2021/10 /23(土) + 神奈川県
+ LANDMARK HALL
+ 開場18:05
開演18:50
+ 一般席
+ 1枚 +
+ 申込済 + + + 支払方法:コンビニ
+
+ + +
+ +
+
+ + + + +
+
+ ■ 演劇女子部「図書館物語~3つのブックマーク~」
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 06 +
+ 2021/11 /14(日) + 東京都
+ 池袋シアターグリーン BIG TREE THEATER
+ 開場10:45
開演11:30
組合せNow/Future
+ 全席指定
+ 1枚 +
+ 申込済 + + + 支払方法:コンビニ
+
+ + +
+ 公演番号
+ 07 +
+ 2021/11 /14(日) + 東京都
+ 池袋シアターグリーン BIG TREE THEATER
+ 開場14:15
開演15:00
組合せPast/Now
+ 全席指定
+ 1枚 +
+ 申込済 + + + 支払方法:コンビニ
+
+ + +
+ 公演番号
+ 08 +
+ 2021/11 /14(日) + 東京都
+ 池袋シアターグリーン BIG TREE THEATER
+ 開場17:45
開演18:30
組合せFuture/Past
+ 全席指定
+ 1枚 +
+ 申込済 + + + 支払方法:コンビニ
+
+ + +
+ +
+
+ + + + +
+
+ ■ 【先々行受付】BEYOOOOONDS結成記念スペシャルライブ2021 ~ポップステップ付点音符.~
+ +
+ + + + + + + + + + + +
+ 公演番号
+ 02 +
+ 2021/10 /19(火) + 東京都
+ 豊洲PIT
+ 開場18:00
開演18:50
+ 一般席
+ 1枚 +
+ 当選
(入金済) + +
+ 支払方法:クレジットカード
+ 入金日:2021/09/17(金)
+
+ + +
+ +
+
+ + + + +
+
+ ■ つばきファクトリー 小野瑞歩バースデーイベント2021
+ +
+ + + + + + + + + + + +
+ 公演番号
+ 02 +
+ 2021/09 /29(水) + 神奈川県
+ LANDMARK HALL
+ 開場18:05
開演18:50
+ 一般席
+ 1枚 +
+ 当選
(入金済) + +
+ 支払方法:コンビニ
+ 入金日:2021/09/12(日)
+
+ + +
+ +
+
+ + + + +
+
+ ■ Hello! Project 2021 秋 「続・花鳥風月」
+ +
+ + + + + + + + + + + +
+ 公演番号
+ 44 +
+ 2021/11 /07(日) + 埼玉県
+ 川口総合文化センター・リリア メインホール
+ 開場17:00
開演18:00
+ 着席指定席
+ 1枚 +
+ 当選
(入金済) + +
+ 支払方法:コンビニ
+ 入金日:2021/08/22(日)
+
+ + +
+ +
+
+ + + + +
先々行受付
+ + +
+
+ ■ Hello! Project 2021 秋 「続・花鳥風月」 先々行受付 (ハロプロ2021秋 先々行 掲載分)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 02 +
+ 2021/09 /23(木) + 千葉県
+ 千葉県文化会館 大ホール
+ 開場 17:00
+ 開演 18:00
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/08/11(水)
+ チケット発送日
2021/09/15
+
+ 公演番号
+ 11 +
+ 2021/10 /02(土) + 埼玉県
+ 三郷市文化会館 大ホール
+ 開場 13:30
+ 開演 14:30
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/08/11(水)
+ +
+ 公演番号
+ 12 +
+ 2021/10 /02(土) + 埼玉県
+ 三郷市文化会館 大ホール
+ 開場 17:00
+ 開演 18:00
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/08/11(水)
+ +
+ 公演番号
+ 19 +
+ 2021/10 /09(土) + 福岡県
+ 福岡国際会議場 メインホール
+ 開場 13:30
+ 開演 14:30
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/08/11(水)
+ +
+ 公演番号
+ 20 +
+ 2021/10 /09(土) + 福岡県
+ 福岡国際会議場 メインホール
+ 開場 17:00
+ 開演 18:00
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/08/11(水)
+ +
+ 公演番号
+ 43 +
+ 2021/11 /07(日) + 埼玉県
+ 川口総合文化センター・リリア メインホール
+ 開場 13:30
+ 開演 14:30
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/08/11(水)
+ +
+ 公演番号
+ 44 +
+ 2021/11 /07(日) + 埼玉県
+ 川口総合文化センター・リリア メインホール
+ 開場 17:00
+ 開演 18:00
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 落選 + 支払方法:カード
+ +
+ 公演番号
+ 47 +
+ 2021/11 /13(土) + 大阪府
+ NHK大阪ホール
+ 開場 13:30
+ 開演 14:30
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/08/11(水)
+ +
+ 公演番号
+ 48 +
+ 2021/11 /13(土) + 大阪府
+ NHK大阪ホール
+ 開場 17:00
+ 開演 18:00
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/08/11(水)
+ +
+ 公演番号
+ 51 +
+ 2021/11 /20(土) + 群馬県
+ 美喜仁桐生文化会館 シルクホール
+ 開場 13:30
+ 開演 14:30
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/08/11(水)
+ +
+ 公演番号
+ 52 +
+ 2021/11 /20(土) + 群馬県
+ 美喜仁桐生文化会館 シルクホール
+ 開場 17:00
+ 開演 18:00
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/08/11(水)
+ +
+ +
+
+ + + + +
+
+ ■ Hello! Project 2021 Summer Sapphire & Ruby 先々行受付 (ハロプロ2021夏 先々行 掲載分)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 05 +
+ 2021/07 /24(土) + 愛知県
+ 名古屋国際会議場センチュリーホール
+ 開場 13:30
+ 開演 14:45
+ 出演チーム Sapphire
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/06/15(火)
+ チケット発送日
2021/07/16
+
+ 公演番号
+ 06 +
+ 2021/07 /24(土) + 愛知県
+ 名古屋国際会議場センチュリーホール
+ 開場 17:00
+ 開演 18:15
+ 出演チーム Sapphire
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/06/15(火)
+ チケット発送日
2021/07/16
+
+ 公演番号
+ 11 +
+ 2021/08 /07(土) + 東京都
+ 中野サンプラザホール
+ 開場 14:00
+ 開演 15:00
+ 出演チーム Ruby
+ + 着席指定席 / 1 枚 ¥6,800
+ + 落選 + 支払方法:カード
+ +
+ 公演番号
+ 12 +
+ 2021/08 /07(土) + 東京都
+ 中野サンプラザホール
+ 開場 17:15
+ 開演 18:15
+ 出演チーム Sapphire
+ + 着席指定席 / 1 枚 ¥6,800
+ + 落選 + 支払方法:カード
+ +
+ 公演番号
+ 13 +
+ 2021/08 /08(日) + 東京都
+ 中野サンプラザホール
+ 開場 14:00
+ 開演 15:00
+ 出演チーム Sapphire
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/06/15(火)
+ チケット発送日
2021/07/30
+
+ 公演番号
+ 14 +
+ 2021/08 /08(日) + 東京都
+ 中野サンプラザホール
+ 開場 17:15
+ 開演 18:15
+ 出演チーム Ruby
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/06/15(火)
+ チケット発送日
2021/07/30
+
+ 公演番号
+ 23 +
+ 2021/09 /04(土) + 東京都
+ TACHIKAWA STAGE GARDEN
+ 開場 14:00
+ 開演 15:00
+ 出演チーム Sapphire
+ + 着席指定席 / 1 枚 ¥6,800
+ + 落選 + 支払方法:カード
+ +
+ 公演番号
+ 24 +
+ 2021/09 /04(土) + 東京都
+ TACHIKAWA STAGE GARDEN
+ 開場 17:15
+ 開演 18:15
+ 出演チーム Ruby
+ + 着席指定席 / 1 枚 ¥6,800
+ + 落選 + 支払方法:カード
+ +
+ 公演番号
+ 25 +
+ 2021/09 /05(日) + 東京都
+ TACHIKAWA STAGE GARDEN
+ 開場 14:00
+ 開演 15:00
+ 出演チーム Ruby
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/06/15(火)
+ チケット発送日
2021/08/27
+
+ 公演番号
+ 26 +
+ 2021/09 /05(日) + 東京都
+ TACHIKAWA STAGE GARDEN
+ 開場 17:15
+ 開演 18:15
+ 出演チーム Sapphire
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/06/15(火)
+ チケット発送日
2021/08/27
+
+ +
+
+ + + + +
+
+ ■ Hello! Project ひなフェス 2021 先々行受付 (ひなフェス 2021 先々行 掲載分)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2021/03 /27(土) + 千葉県
+ 幕張メッセ 国際展示場 1・2ホール
+ 開場 10:45
+ 開演 12:00
+
+ + 着席指定席 / 1 枚 ¥7,300
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/02/26(金)
+ チケット発送日
2021/03/19
+
+ 公演番号
+ 03 +
+ 2021/03 /28(日) + 千葉県
+ 幕張メッセ 国際展示場 1・2ホール
+ 開場 10:15
+ 開演 11:30
+
+ + 着席指定席 / 1 枚 ¥7,300
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/02/26(金)
+ チケット発送日
2021/03/19
+
+ 公演番号
+ 04 +
+ 2021/03 /28(日) + 千葉県
+ 幕張メッセ 国際展示場 1・2ホール
+ 開場 15:15
+ 開演 16:30
+
+ + 着席指定席 / 1 枚 ¥7,300
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/02/26(金)
+ チケット発送日
2021/03/19
+
+ +
+
+ + + + +
+
+ ■ Hello! Project 2021 春 「花鳥風月」 先々行受付 (ハロプロ2021春 先々行 掲載分)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2021/03 /13(土) + 東京都
+ オリンパスホール八王子
+ 開場 14:00
+ 開演 15:00
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/02/15(月)
+ チケット発送日
2021/03/05
+
+ 公演番号
+ 02 +
+ 2021/03 /13(土) + 東京都
+ オリンパスホール八王子
+ 開場 17:15
+ 開演 18:15
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/02/15(月)
+ チケット発送日
2021/03/05
+
+ 公演番号
+ 03 +
+ 2021/03 /14(日) + 東京都
+ オリンパスホール八王子
+ 開場 14:00
+ 開演 15:00
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/02/15(月)
+ チケット発送日
2021/03/05
+
+ 公演番号
+ 25 +
+ 2021/04 /24(土) + 東京都
+ TACHIKAWA STAGE GARDEN
+ 開場 14:00
+ 開演 15:00
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/02/15(月)
+ チケット発送日
2021/04/16
+
+ 公演番号
+ 32 +
+ 2021/04 /25(日) + 千葉県
+ 千葉県文化会館 大ホール
+ 開場 17:15
+ 開演 18:15
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/02/15(月)
+ チケット発送日
2021/04/16
+
+ 公演番号
+ 33 +
+ 2021/04 /29(木) + 愛知県
+ 名古屋市公会堂 大ホール
+ 開場 14:00
+ 開演 15:00
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/02/15(月)
+ チケット発送日
2021/04/21
+
+ 公演番号
+ 34 +
+ 2021/04 /29(木) + 愛知県
+ 名古屋市公会堂 大ホール
+ 開場 17:15
+ 開演 18:15
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/02/15(月)
+ チケット発送日
2021/04/21
+
+ 公演番号
+ 65 +
+ 2021/05 /23(日) + 千葉県
+ 千葉県文化会館 大ホール
+ 開場 14:00
+ 開演 15:00
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/02/15(月)
+ チケット発送日
2021/05/14
+
+ 公演番号
+ 66 +
+ 2021/05 /23(日) + 千葉県
+ 千葉県文化会館 大ホール
+ 開場 17:15
+ 開演 18:15
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2021/02/15(月)
+ チケット発送日
2021/05/14
+
+ +
+
+ + + + +
+
+ ■ Hello! Project 2021 Winter ~STEP BY STEP~ 先々行受付 (ハロプロ2021冬 先々行 掲載分)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2021/01 /02(土) + 東京都
+ 中野サンプラザ
+ 開場 14:15
+ 開演 15:30
+
+ + 着席指定席 / 1 枚 ¥6,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/11/25(水)
+ チケット発送日
2020/12/23
+
+ 公演番号
+ 03 +
+ 2021/01 /03(日) + 東京都
+ 中野サンプラザ
+ 開場 11:00
+ 開演 12:15
+
+ + 着席指定席 / 1 枚 ¥6,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/11/25(水)
+ チケット発送日
2020/12/23
+
+ 公演番号
+ 04 +
+ 2021/01 /03(日) + 東京都
+ 中野サンプラザ
+ 開場 14:30
+ 開演 15:45
+
+ + 着席指定席 / 1 枚 ¥6,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/11/25(水)
+ チケット発送日
2020/12/23
+
+ 公演番号
+ 05 +
+ 2021/01 /03(日) + 東京都
+ 中野サンプラザ
+ 開場 18:00
+ 開演 19:15
+
+ + 着席指定席 / 1 枚 ¥6,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/11/25(水)
+ チケット発送日
2020/12/23
+
+ 公演番号
+ 32 +
+ 2021/02 /07(日) + 東京都
+ 中野サンプラザ
+ 開場 11:00
+ 開演 12:15
+
+ + 着席指定席 / 1 枚 ¥6,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/11/25(水)
+ チケット発送日
2021/01/29
+
+ 公演番号
+ 33 +
+ 2021/02 /07(日) + 東京都
+ 中野サンプラザ
+ 開場 14:30
+ 開演 15:45
+
+ + 着席指定席 / 1 枚 ¥6,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/11/25(水)
+ チケット発送日
2021/01/29
+
+ 公演番号
+ 34 +
+ 2021/02 /07(日) + 東京都
+ 中野サンプラザ
+ 開場 17:35
+ 開演 18:20
+
+ + 着席指定席 / 1 枚 ¥6,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/11/25(水)
+ チケット発送日
2021/01/29
+
+ 公演番号
+ 35 +
+ 2021/02 /11(木) + 神奈川県
+ ハーモニーホール座間 大ホール
+ 開場 14:45
+ 開演 15:45
+
+ + 着席指定席 / 1 枚 ¥6,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/11/25(水)
+ チケット発送日
2021/02/04
+
+ 公演番号
+ 36 +
+ 2021/02 /11(木) + 神奈川県
+ ハーモニーホール座間 大ホール
+ 開場 17:45
+ 開演 18:30
+
+ + 着席指定席 / 1 枚 ¥6,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/11/25(水)
+ チケット発送日
2021/02/04
+
+ 公演番号
+ 45 +
+ 2021/02 /23(火) + 東京都
+ 中野サンプラザ
+ 開場 14:15
+ 開演 15:30
+
+ + 着席指定席 / 1 枚 ¥6,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/11/25(水)
+ チケット発送日
2021/02/16
+
+ 公演番号
+ 46 +
+ 2021/02 /23(火) + 東京都
+ 中野サンプラザ
+ 開場 17:30
+ 開演 18:30
+
+ + 着席指定席 / 1 枚 ¥6,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/11/25(水)
+ チケット発送日
2021/02/16
+
+ +
+
+ + + + +
+
+ ■ Hello! Project 2020 ~The Ballad~ 先々行受付 (ハロプロ2020 第3弾 先々行 掲載分)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 133 +
+ 2020/12 /13(日) + 埼玉県
+ 和光市民文化センター サンアゼリア 大ホール
+ 開場 13:30
+ 開演 14:30
+
+ + 着席指定席 / 1 枚 ¥5,500
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/11/07(土)
+ チケット発送日
2020/12/04
+
+ 公演番号
+ 134 +
+ 2020/12 /13(日) + 埼玉県
+ 和光市民文化センター サンアゼリア 大ホール
+ 開場 17:15
+ 開演 18:15
+
+ + 着席指定席 / 1 枚 ¥5,500
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/11/07(土)
+ チケット発送日
2020/12/04
+
+ +
+
+ + + + +
+
+ ■ Juice=Juice コンサート2020 ~続いていくSTORY~ 宮本佳林卒業スペシャル 先々行受付 (宮本佳林卒業公演 先々行 掲載分)
+
+ + + + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2020/12 /10(木) + 東京都
+ 日本武道館
+ 開場 17:15
+ 開演 18:30
+
+ + 着席指定席 / 1 枚 ¥7,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/10/28(水)
+ チケット発送日
2020/12/01
+
+ +
+
+ + + + +
+
+ ■ アンジュルム コンサート2020 ~起承転結~ 船木結卒業スペシャル 先々行受付 (船木結卒業公演 先々行 掲載分)
+
+ + + + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2020/12 /09(水) + 東京都
+ 日本武道館
+ 開場 17:15
+ 開演 18:30
+
+ + 着席指定席 / 1 枚 ¥7,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/10/28(水)
+ チケット発送日
2020/12/01
+
+ +
+
+ + + + +
+
+ ■ Hello! Project 2020 ~The Ballad~ Special Number 先々行受付 (ハロプロ2020武道館 先々行 掲載分)
+
+ + + + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2020/12 /02(水) + 東京都
+ 日本武道館
+ 開場 17:15
+ 開演 18:30
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/10/23(金)
+ チケット発送日
2020/11/24
+
+ +
+
+ + + + +
+
+ ■ Hello! Project 2020 ~The Ballad~ 先々行受付 (ハロプロ2020 11月東京公演 掲載分)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 129 +
+ 2020/11 /23(月) + 東京都
+ セルリアンタワー東急ホテル ボールルーム
+ 開場 13:30
+ 開演 14:30
+
+ + 着席指定席 / 1 枚 ¥6,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/10/16(金)
+ チケット発送日
2020/11/13
+
+ 公演番号
+ 130 +
+ 2020/11 /23(月) + 東京都
+ セルリアンタワー東急ホテル ボールルーム
+ 開場 17:15
+ 開演 18:15
+
+ + 着席指定席 / 1 枚 ¥6,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/10/16(金)
+ チケット発送日
2020/11/13
+
+ +
+
+ + + + +
+
+ ■ Hello! Project 2020 Autumn ~The Ballad~ Extra Number 先々行受付 (ハロプロ2020武道館 先々行 掲載分)
+
+ + + + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2020/10 /12(月) + 東京都
+ 日本武道館
+ 開場 16:30
+ 開演 18:00
+
+ + 着席指定席 / 1 枚 ¥6,800
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/09/16(水)
+ チケット発送日
2020/10/02
+
+ +
+
+ + + + +
+
+ ■ Hello! Project 2020 ~The Ballad~ 先々行受付 (ハロプロ2020 先々行 掲載分)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2020/09 /19(土) + 神奈川県
+ ハーモニーホール座間 大ホール
+ 開場 13:30
+ 開演 14:30
+
+ + 着席指定席 / 1 枚 ¥5,500
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/08/25(火)
+ チケット発送日
2020/09/11
+
+ 公演番号
+ 05 +
+ 2020/09 /20(日) + 東京都
+ 大田区民ホール・アプリコ 大ホール
+ 開場 13:30
+ 開演 14:30
+
+ + 着席指定席 / 1 枚 ¥5,500
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/08/25(火)
+ チケット発送日
2020/09/11
+
+ 公演番号
+ 21 +
+ 2020/09 /27(日) + 東京都
+ 町田市民ホール
+ 開場 13:30
+ 開演 14:30
+
+ + 着席指定席 / 1 枚 ¥6,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/08/25(火)
+ チケット発送日
2020/09/18
+
+ 公演番号
+ 25 +
+ 2020/10 /03(土) + 東京都
+ TACHIKAWA STAGE GARDEN
+ 開場 13:30
+ 開演 14:30
+
+ + 着席指定席 / 1 枚 ¥5,500
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/08/25(火)
+ チケット発送日
2020/09/25
+
+ 公演番号
+ 45 +
+ 2020/10 /17(土) + 神奈川県
+ ハーモニーホール座間 大ホール
+ 開場 13:30
+ 開演 14:30
+
+ + 着席指定席 / 1 枚 ¥5,500
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/08/25(火)
+ チケット発送日
2020/10/09
+
+ +
+
+ + + + +
+
+ ■ Hello! Project 2020 Summer COVERS ~The Ballad~ 先々行受付 (ハロプロ2020Summer愛知 先々行 掲載分)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 30 +
+ 2020/08 /29(土) + 愛知県
+ 日本特殊陶業市民会館 フォレストホール
+ 開場 13:45
+ 開演 15:15
+ 出演 Bチーム
+ + 着席指定席 / 1 枚 ¥5,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/07/18(土)
+ チケット発送日
2020/08/21
+
+ 公演番号
+ 31 +
+ 2020/08 /29(土) + 愛知県
+ 日本特殊陶業市民会館 フォレストホール
+ 開場 17:30
+ 開演 19:00
+ 出演 Cチーム
+ + 着席指定席 / 1 枚 ¥5,000
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/07/18(土)
+ チケット発送日
2020/08/21
+
+ +
+
+ + + + +
+
+ ■ モーニング娘。’20 小田さくらバースデーイベント ~さくらのしらべ9~ 先々行受付 (小田さくらBDイベント2020 掲載分)
+
+ + + + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2020/07 /28(火) + 東京都
+ コットンクラブ
+ 開場 16:30
+ 開演 17:00
+
+ + 一般席 / 1 枚 ¥5,200
+ + 当選
(入金済)
+ 支払方法:カード
入金日:2020/07/07(火)
+ +
+ +
+
+ + + +
+ +
+
+ +
+ + + +
+ + + diff --git a/expo/features/upfc/scraper/testdata/integration-test.exepected.json b/expo/features/upfc/scraper/testdata/integration-test.exepected.json new file mode 100644 index 00000000..67e1792a --- /dev/null +++ b/expo/features/upfc/scraper/testdata/integration-test.exepected.json @@ -0,0 +1,663 @@ +[ + { + "name": "【NEXT先行】鈴木愛理 LIVE 2021~26/27~ @ 大阪・名古屋", + "applicationStartDate": "2021-09-15T15:00:00.000Z", + "applicationDueDate": "2021-09-21T15:00:00.000Z", + "paymentOpenDate": "2021-09-23T15:00:00.000Z", + "paymentDueDate": "2021-09-29T15:00:00.000Z", + "applicationID": "ES_2258", + "tickets": [] + }, + { + "name": "ENPLEX × Hello! Project 名古屋定期イベント「アンジュルム 竹内朱莉 ‶竹を割ったような″イベント in 名古屋」", + "applicationStartDate": "2021-09-15T15:00:00.000Z", + "applicationDueDate": "2021-09-27T15:00:00.000Z", + "paymentOpenDate": "2021-09-29T15:00:00.000Z", + "paymentDueDate": "2021-10-05T15:00:00.000Z", + "applicationID": "ES_2257", + "tickets": [] + }, + { + "name": "【NEXT先行】工藤遥バースデーイベント2021 ~22nd Best day ever~きょうやすSP", + "applicationStartDate": "2021-09-15T15:00:00.000Z", + "applicationDueDate": "2021-09-23T15:00:00.000Z", + "paymentOpenDate": "2021-09-26T15:00:00.000Z", + "paymentDueDate": "2021-10-02T15:00:00.000Z", + "applicationID": "ES_2256", + "tickets": [] + }, + { + "name": "【NEXT先行】宮崎由加ファンクラブイベント2021~Halloween yukanya~", + "applicationStartDate": "2021-09-14T15:00:00.000Z", + "applicationDueDate": "2021-09-21T15:00:00.000Z", + "paymentOpenDate": "2021-09-23T15:00:00.000Z", + "paymentDueDate": "2021-09-29T15:00:00.000Z", + "applicationID": "ES_2255", + "tickets": [] + }, + { + "name": "Juice=Juice新メンバー 有澤一華・入江里咲・江端妃咲FCイベント2021", + "applicationStartDate": "2021-09-14T15:00:00.000Z", + "applicationDueDate": "2021-09-28T15:00:00.000Z", + "paymentOpenDate": "2021-09-30T15:00:00.000Z", + "paymentDueDate": "2021-10-05T15:00:00.000Z", + "applicationID": "ES_2253", + "tickets": [] + }, + { + "name": "アンジュルム 上國料萌衣&笠原桃奈バースデーイベント2021", + "applicationStartDate": "2021-09-13T15:00:00.000Z", + "applicationDueDate": "2021-09-27T15:00:00.000Z", + "paymentOpenDate": "2021-09-30T15:00:00.000Z", + "paymentDueDate": "2021-10-05T15:00:00.000Z", + "applicationID": "ES_2250", + "tickets": [] + }, + { + "name": "アンジュルム コンサート2021 「桃源郷 ~笠原桃奈 卒業スペシャル~」", + "applicationStartDate": "2021-09-12T15:00:00.000Z", + "applicationDueDate": "2021-09-23T15:00:00.000Z", + "paymentOpenDate": "2021-09-29T15:00:00.000Z", + "paymentDueDate": "2021-10-03T15:00:00.000Z", + "applicationID": "ES_2249", + "tickets": [] + }, + { + "name": "演劇女子部「図書館物語~3つのブックマーク~」", + "applicationStartDate": "2021-09-12T15:00:00.000Z", + "applicationDueDate": "2021-09-21T15:00:00.000Z", + "paymentOpenDate": "2021-09-27T15:00:00.000Z", + "paymentDueDate": "2021-10-02T15:00:00.000Z", + "applicationID": "ES_2247", + "tickets": [] + }, + { + "name": "アンジュルム 笠原桃奈バースデーイベント2021", + "applicationStartDate": "2021-09-09T15:00:00.000Z", + "applicationDueDate": "2021-09-27T15:00:00.000Z", + "paymentOpenDate": "2021-09-29T15:00:00.000Z", + "paymentDueDate": "2021-10-05T15:00:00.000Z", + "applicationID": "ES_2246", + "tickets": [] + }, + { + "name": "BEYOOOOONDS/雨ノ森 川海 岡村美波バースデーイベント2021", + "applicationStartDate": "2021-09-09T15:00:00.000Z", + "applicationDueDate": "2021-09-26T15:00:00.000Z", + "paymentOpenDate": "2021-09-28T15:00:00.000Z", + "paymentDueDate": "2021-10-03T15:00:00.000Z", + "applicationID": "ES_2245", + "tickets": [] + }, + { + "name": "【当日券予約】ENPLEX × Hello! Project 名古屋定期イベント「ハロプロ研修生イベント in 名古屋」", + "applicationStartDate": "2021-09-08T15:00:00.000Z", + "applicationDueDate": "2021-09-12T15:00:00.000Z", + "paymentOpenDate": "2021-09-14T15:00:00.000Z", + "paymentDueDate": "2021-09-20T15:00:00.000Z", + "applicationID": "ES_2244", + "tickets": [] + }, + { + "name": "BEYOOOOONDS結成記念スペシャルライブ2021 ~ポップステップ付点音符.~", + "applicationStartDate": "2021-09-07T15:00:00.000Z", + "applicationDueDate": "2021-09-22T15:00:00.000Z", + "paymentOpenDate": "2021-09-26T15:00:00.000Z", + "paymentDueDate": "2021-10-02T15:00:00.000Z", + "applicationID": "ES_2242", + "tickets": [] + }, + { + "name": "アンジュルム 日本武道館 先々行", + "applicationStartDate": "2021-09-12T15:00:00.000Z", + "applicationDueDate": "2021-09-19T15:00:00.000Z", + "paymentOpenDate": "2021-09-21T15:00:00.000Z", + "paymentDueDate": "2021-09-29T15:00:00.000Z", + "applicationID": "DM_316", + "tickets": [] + }, + { + "name": "Juice=Juice横浜アリーナ先々行", + "applicationStartDate": "2021-09-23T15:00:00.000Z", + "applicationDueDate": "2021-09-28T15:00:00.000Z", + "paymentOpenDate": "2021-09-28T15:00:00.000Z", + "paymentDueDate": "2021-10-02T15:00:00.000Z", + "applicationID": "DM_317", + "tickets": [] + }, + { + "name": "モーニング娘。’21 日本武道館 先々行", + "applicationStartDate": "2021-09-23T15:00:00.000Z", + "applicationDueDate": "2021-09-28T15:00:00.000Z", + "paymentOpenDate": "2021-09-28T15:00:00.000Z", + "paymentDueDate": "2021-10-02T15:00:00.000Z", + "applicationID": "DM_318", + "tickets": [] + }, + { + "name": "【先々行受付】BEYOOOOONDS結成記念スペシャルライブ2021 ~ポップステップ付点音符.~", + "tickets": [ + { + "venue": "東京都 豊洲PIT", + "openAt": "2021-10-19T09:00:00.000Z", + "startAt": "2021-10-19T09:50:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "つばきファクトリー 小野瑞歩バースデーイベント2021", + "tickets": [ + { + "venue": "神奈川県 LANDMARK HALL", + "openAt": "2021-09-29T09:05:00.000Z", + "startAt": "2021-09-29T09:50:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project 2021 秋 「続・花鳥風月」", + "tickets": [ + { + "venue": "埼玉県 川口総合文化センター・リリア メインホール", + "openAt": "2021-11-07T08:00:00.000Z", + "startAt": "2021-11-07T09:00:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project 2021 秋 「続・花鳥風月」 先々行受付 (ハロプロ2021秋 先々行 掲載分)", + "tickets": [ + { + "venue": "千葉県 千葉県文化会館 大ホール", + "openAt": "2021-09-23T08:00:00.000Z", + "startAt": "2021-09-23T09:00:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "埼玉県 三郷市文化会館 大ホール", + "openAt": "2021-10-02T04:30:00.000Z", + "startAt": "2021-10-02T05:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "埼玉県 三郷市文化会館 大ホール", + "openAt": "2021-10-02T08:00:00.000Z", + "startAt": "2021-10-02T09:00:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "福岡県 福岡国際会議場 メインホール", + "openAt": "2021-10-09T04:30:00.000Z", + "startAt": "2021-10-09T05:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "福岡県 福岡国際会議場 メインホール", + "openAt": "2021-10-09T08:00:00.000Z", + "startAt": "2021-10-09T09:00:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "埼玉県 川口総合文化センター・リリア メインホール", + "openAt": "2021-11-07T04:30:00.000Z", + "startAt": "2021-11-07T05:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "埼玉県 川口総合文化センター・リリア メインホール", + "openAt": "2021-11-07T08:00:00.000Z", + "startAt": "2021-11-07T09:00:00.000Z", + "status": "落選", + "num": 1 + }, + { + "venue": "大阪府 NHK大阪ホール", + "openAt": "2021-11-13T04:30:00.000Z", + "startAt": "2021-11-13T05:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "大阪府 NHK大阪ホール", + "openAt": "2021-11-13T08:00:00.000Z", + "startAt": "2021-11-13T09:00:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "群馬県 美喜仁桐生文化会館 シルクホール", + "openAt": "2021-11-20T04:30:00.000Z", + "startAt": "2021-11-20T05:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "群馬県 美喜仁桐生文化会館 シルクホール", + "openAt": "2021-11-20T08:00:00.000Z", + "startAt": "2021-11-20T09:00:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project 2021 Summer Sapphire & Ruby 先々行受付 (ハロプロ2021夏 先々行 掲載分)", + "tickets": [ + { + "venue": "愛知県 名古屋国際会議場センチュリーホール", + "openAt": "2021-07-24T04:30:00.000Z", + "startAt": "2021-07-24T05:45:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "愛知県 名古屋国際会議場センチュリーホール", + "openAt": "2021-07-24T08:00:00.000Z", + "startAt": "2021-07-24T09:15:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザホール", + "openAt": "2021-08-07T05:00:00.000Z", + "startAt": "2021-08-07T06:00:00.000Z", + "status": "落選", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザホール", + "openAt": "2021-08-07T08:15:00.000Z", + "startAt": "2021-08-07T09:15:00.000Z", + "status": "落選", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザホール", + "openAt": "2021-08-08T05:00:00.000Z", + "startAt": "2021-08-08T06:00:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザホール", + "openAt": "2021-08-08T08:15:00.000Z", + "startAt": "2021-08-08T09:15:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 TACHIKAWA STAGE GARDEN", + "openAt": "2021-09-04T05:00:00.000Z", + "startAt": "2021-09-04T06:00:00.000Z", + "status": "落選", + "num": 1 + }, + { + "venue": "東京都 TACHIKAWA STAGE GARDEN", + "openAt": "2021-09-04T08:15:00.000Z", + "startAt": "2021-09-04T09:15:00.000Z", + "status": "落選", + "num": 1 + }, + { + "venue": "東京都 TACHIKAWA STAGE GARDEN", + "openAt": "2021-09-05T05:00:00.000Z", + "startAt": "2021-09-05T06:00:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 TACHIKAWA STAGE GARDEN", + "openAt": "2021-09-05T08:15:00.000Z", + "startAt": "2021-09-05T09:15:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project ひなフェス 2021 先々行受付 (ひなフェス 2021 先々行 掲載分)", + "tickets": [ + { + "venue": "千葉県 幕張メッセ 国際展示場 1・2ホール", + "openAt": "2021-03-27T01:45:00.000Z", + "startAt": "2021-03-27T03:00:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "千葉県 幕張メッセ 国際展示場 1・2ホール", + "openAt": "2021-03-28T01:15:00.000Z", + "startAt": "2021-03-28T02:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "千葉県 幕張メッセ 国際展示場 1・2ホール", + "openAt": "2021-03-28T06:15:00.000Z", + "startAt": "2021-03-28T07:30:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project 2021 春 「花鳥風月」 先々行受付 (ハロプロ2021春 先々行 掲載分)", + "tickets": [ + { + "venue": "東京都 オリンパスホール八王子", + "openAt": "2021-03-13T05:00:00.000Z", + "startAt": "2021-03-13T06:00:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 オリンパスホール八王子", + "openAt": "2021-03-13T08:15:00.000Z", + "startAt": "2021-03-13T09:15:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 オリンパスホール八王子", + "openAt": "2021-03-14T05:00:00.000Z", + "startAt": "2021-03-14T06:00:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 TACHIKAWA STAGE GARDEN", + "openAt": "2021-04-24T05:00:00.000Z", + "startAt": "2021-04-24T06:00:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "千葉県 千葉県文化会館 大ホール", + "openAt": "2021-04-25T08:15:00.000Z", + "startAt": "2021-04-25T09:15:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "愛知県 名古屋市公会堂 大ホール", + "openAt": "2021-04-29T05:00:00.000Z", + "startAt": "2021-04-29T06:00:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "愛知県 名古屋市公会堂 大ホール", + "openAt": "2021-04-29T08:15:00.000Z", + "startAt": "2021-04-29T09:15:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "千葉県 千葉県文化会館 大ホール", + "openAt": "2021-05-23T05:00:00.000Z", + "startAt": "2021-05-23T06:00:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "千葉県 千葉県文化会館 大ホール", + "openAt": "2021-05-23T08:15:00.000Z", + "startAt": "2021-05-23T09:15:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project 2021 Winter ~STEP BY STEP~ 先々行受付 (ハロプロ2021冬 先々行 掲載分)", + "tickets": [ + { + "venue": "東京都 中野サンプラザ", + "openAt": "2021-01-02T05:15:00.000Z", + "startAt": "2021-01-02T06:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザ", + "openAt": "2021-01-03T02:00:00.000Z", + "startAt": "2021-01-03T03:15:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザ", + "openAt": "2021-01-03T05:30:00.000Z", + "startAt": "2021-01-03T06:45:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザ", + "openAt": "2021-01-03T09:00:00.000Z", + "startAt": "2021-01-03T10:15:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザ", + "openAt": "2021-02-07T02:00:00.000Z", + "startAt": "2021-02-07T03:15:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザ", + "openAt": "2021-02-07T05:30:00.000Z", + "startAt": "2021-02-07T06:45:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザ", + "openAt": "2021-02-07T08:35:00.000Z", + "startAt": "2021-02-07T09:20:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "神奈川県 ハーモニーホール座間 大ホール", + "openAt": "2021-02-11T05:45:00.000Z", + "startAt": "2021-02-11T06:45:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "神奈川県 ハーモニーホール座間 大ホール", + "openAt": "2021-02-11T08:45:00.000Z", + "startAt": "2021-02-11T09:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザ", + "openAt": "2021-02-23T05:15:00.000Z", + "startAt": "2021-02-23T06:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザ", + "openAt": "2021-02-23T08:30:00.000Z", + "startAt": "2021-02-23T09:30:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project 2020 ~The Ballad~ 先々行受付 (ハロプロ2020 第3弾 先々行 掲載分)", + "tickets": [ + { + "venue": "埼玉県 和光市民文化センター サンアゼリア 大ホール", + "openAt": "2020-12-13T04:30:00.000Z", + "startAt": "2020-12-13T05:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "埼玉県 和光市民文化センター サンアゼリア 大ホール", + "openAt": "2020-12-13T08:15:00.000Z", + "startAt": "2020-12-13T09:15:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Juice=Juice コンサート2020 ~続いていくSTORY~ 宮本佳林卒業スペシャル 先々行受付 (宮本佳林卒業公演 先々行 掲載分)", + "tickets": [ + { + "venue": "東京都 日本武道館", + "openAt": "2020-12-10T08:15:00.000Z", + "startAt": "2020-12-10T09:30:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "アンジュルム コンサート2020 ~起承転結~ 船木結卒業スペシャル 先々行受付 (船木結卒業公演 先々行 掲載分)", + "tickets": [ + { + "venue": "東京都 日本武道館", + "openAt": "2020-12-09T08:15:00.000Z", + "startAt": "2020-12-09T09:30:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project 2020 ~The Ballad~ Special Number 先々行受付 (ハロプロ2020武道館 先々行 掲載分)", + "tickets": [ + { + "venue": "東京都 日本武道館", + "openAt": "2020-12-02T08:15:00.000Z", + "startAt": "2020-12-02T09:30:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project 2020 ~The Ballad~ 先々行受付 (ハロプロ2020 11月東京公演 掲載分)", + "tickets": [ + { + "venue": "東京都 セルリアンタワー東急ホテル ボールルーム", + "openAt": "2020-11-23T04:30:00.000Z", + "startAt": "2020-11-23T05:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 セルリアンタワー東急ホテル ボールルーム", + "openAt": "2020-11-23T08:15:00.000Z", + "startAt": "2020-11-23T09:15:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project 2020 Autumn ~The Ballad~ Extra Number 先々行受付 (ハロプロ2020武道館 先々行 掲載分)", + "tickets": [ + { + "venue": "東京都 日本武道館", + "openAt": "2020-10-12T07:30:00.000Z", + "startAt": "2020-10-12T09:00:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project 2020 ~The Ballad~ 先々行受付 (ハロプロ2020 先々行 掲載分)", + "tickets": [ + { + "venue": "神奈川県 ハーモニーホール座間 大ホール", + "openAt": "2020-09-19T04:30:00.000Z", + "startAt": "2020-09-19T05:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 大田区民ホール・アプリコ 大ホール", + "openAt": "2020-09-20T04:30:00.000Z", + "startAt": "2020-09-20T05:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 町田市民ホール", + "openAt": "2020-09-27T04:30:00.000Z", + "startAt": "2020-09-27T05:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 TACHIKAWA STAGE GARDEN", + "openAt": "2020-10-03T04:30:00.000Z", + "startAt": "2020-10-03T05:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "神奈川県 ハーモニーホール座間 大ホール", + "openAt": "2020-10-17T04:30:00.000Z", + "startAt": "2020-10-17T05:30:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project 2020 Summer COVERS ~The Ballad~ 先々行受付 (ハロプロ2020Summer愛知 先々行 掲載分)", + "tickets": [ + { + "venue": "愛知県 日本特殊陶業市民会館 フォレストホール", + "openAt": "2020-08-29T04:45:00.000Z", + "startAt": "2020-08-29T06:15:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "愛知県 日本特殊陶業市民会館 フォレストホール", + "openAt": "2020-08-29T08:30:00.000Z", + "startAt": "2020-08-29T10:00:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "モーニング娘。’20 小田さくらバースデーイベント ~さくらのしらべ9~ 先々行受付 (小田さくらBDイベント2020 掲載分)", + "tickets": [ + { + "venue": "東京都 コットンクラブ", + "openAt": "2020-07-28T07:30:00.000Z", + "startAt": "2020-07-28T08:00:00.000Z", + "status": "入金済", + "num": 1 + } + ] + } +] diff --git a/expo/features/upfc/scraper/testdata/valid-available-applications-exe.expected.json b/expo/features/upfc/scraper/testdata/valid-available-applications-exe.expected.json new file mode 100644 index 00000000..ac2e34e2 --- /dev/null +++ b/expo/features/upfc/scraper/testdata/valid-available-applications-exe.expected.json @@ -0,0 +1,29 @@ +[ + { + "name": "アンジュルム 日本武道館 先々行", + "applicationStartDate": "2021-09-12T15:00:00.000Z", + "applicationDueDate": "2021-09-19T15:00:00.000Z", + "paymentOpenDate": "2021-09-21T15:00:00.000Z", + "paymentDueDate": "2021-09-29T15:00:00.000Z", + "applicationID": "DM_316", + "tickets": [] + }, + { + "name": "Juice=Juice横浜アリーナ先々行", + "applicationStartDate": "2021-09-23T15:00:00.000Z", + "applicationDueDate": "2021-09-28T15:00:00.000Z", + "paymentOpenDate": "2021-09-28T15:00:00.000Z", + "paymentDueDate": "2021-10-02T15:00:00.000Z", + "applicationID": "DM_317", + "tickets": [] + }, + { + "name": "モーニング娘。’21 日本武道館 先々行", + "applicationStartDate": "2021-09-23T15:00:00.000Z", + "applicationDueDate": "2021-09-28T15:00:00.000Z", + "paymentOpenDate": "2021-09-28T15:00:00.000Z", + "paymentDueDate": "2021-10-02T15:00:00.000Z", + "applicationID": "DM_318", + "tickets": [] + } +] diff --git a/expo/features/upfc/scraper/testdata/valid-available-applications-exe.html b/expo/features/upfc/scraper/testdata/valid-available-applications-exe.html new file mode 100644 index 00000000..bf640aba --- /dev/null +++ b/expo/features/upfc/scraper/testdata/valid-available-applications-exe.html @@ -0,0 +1,215 @@ + + + + + + + + + +Hello! Project + + + + +
+ +
+ + +
+ +
+ + +
+ +

チケット/イベント受付(先々行受付)

+
+ +
+ + +
+
+ +
+ + + + + + + + + + + + +

チケット/イベント受付(先々行受付) 受付&確認

+
+ + アンジュルム 日本武道館 先々行 + +
+ + 受付期間  :2021年09月13日(月)17時00分~2021年09月20日(月)23時00分まで
+ 受付確認期間:2021年09月13日(月)17時00分~2021年09月20日(月)23時00分まで
+ 当落発表期間:2021年09月22日(水)16時00分~2021年09月30日(木)23時00分まで
+
+
+ ※エグゼクティブ会員限定 +
+
+
+ +
+
+
+
+ + Juice=Juice横浜アリーナ先々行 + +
+ + 受付期間  :2021年09月24日(金)17時00分~2021年09月29日(水)12時00分まで
+ 受付確認期間:2021年09月24日(金)17時00分~2021年09月29日(水)12時00分まで
+ 当落発表期間:2021年09月29日(水)17時00分~2021年10月03日(日)23時00分まで
+
+
+ ※エグゼクティブ会員限定(ご来場の際は、チケット名義人のエグゼクティブパスまたは本人確認書類をご持参ください。) +
+
+
+ +
+
+
+
+ + モーニング娘。’21 日本武道館 先々行 + +
+ + 受付期間  :2021年09月24日(金)17時00分~2021年09月29日(水)12時00分まで
+ 受付確認期間:2021年09月24日(金)17時00分~2021年09月29日(水)12時00分まで
+ 当落発表期間:2021年09月29日(水)17時00分~2021年10月03日(日)23時00分まで
+
+
+ ※エグゼクティブ会員限定(ご来場の際は、チケット名義人のエグゼクティブパスまたは本人確認書類をご持参ください。) +
+
+
+ +
+
+
+
+ +

+ +
+ +

+ +
+
+
+
+
+ + + +
+ + + + diff --git a/expo/features/upfc/scraper/testdata/valid-available-applications.expected.json b/expo/features/upfc/scraper/testdata/valid-available-applications.expected.json new file mode 100644 index 00000000..1b2d84f3 --- /dev/null +++ b/expo/features/upfc/scraper/testdata/valid-available-applications.expected.json @@ -0,0 +1,119 @@ +[ + { + "name": "【NEXT先行】鈴木愛理 LIVE 2021~26/27~ @ 大阪・名古屋", + "applicationStartDate": "2021-09-15T15:00:00.000Z", + "applicationDueDate": "2021-09-21T15:00:00.000Z", + "paymentOpenDate": "2021-09-23T15:00:00.000Z", + "paymentDueDate": "2021-09-29T15:00:00.000Z", + "applicationID": "ES_2258", + "tickets": [] + }, + { + "name": "ENPLEX × Hello! Project 名古屋定期イベント「アンジュルム 竹内朱莉 ‶竹を割ったような″イベント in 名古屋」", + "applicationStartDate": "2021-09-15T15:00:00.000Z", + "applicationDueDate": "2021-09-27T15:00:00.000Z", + "paymentOpenDate": "2021-09-29T15:00:00.000Z", + "paymentDueDate": "2021-10-05T15:00:00.000Z", + "applicationID": "ES_2257", + "tickets": [] + }, + { + "name": "【NEXT先行】工藤遥バースデーイベント2021 ~22nd Best day ever~きょうやすSP", + "applicationStartDate": "2021-09-15T15:00:00.000Z", + "applicationDueDate": "2021-09-23T15:00:00.000Z", + "paymentOpenDate": "2021-09-26T15:00:00.000Z", + "paymentDueDate": "2021-10-02T15:00:00.000Z", + "applicationID": "ES_2256", + "tickets": [] + }, + { + "name": "【NEXT先行】宮崎由加ファンクラブイベント2021~Halloween yukanya~", + "applicationStartDate": "2021-09-14T15:00:00.000Z", + "applicationDueDate": "2021-09-21T15:00:00.000Z", + "paymentOpenDate": "2021-09-23T15:00:00.000Z", + "paymentDueDate": "2021-09-29T15:00:00.000Z", + "applicationID": "ES_2255", + "tickets": [] + }, + { + "name": "【2次受付】M-line Special 2021~Make a Wish!~【10月公演】", + "applicationStartDate": "2021-09-13T15:00:00.000Z", + "applicationDueDate": "2021-09-20T15:00:00.000Z", + "paymentOpenDate": "2021-09-20T15:00:00.000Z", + "paymentDueDate": "2021-09-25T15:00:00.000Z", + "applicationID": "ES_2254", + "tickets": [] + }, + { + "name": "Juice=Juice新メンバー 有澤一華・入江里咲・江端妃咲FCイベント2021", + "applicationStartDate": "2021-09-14T15:00:00.000Z", + "applicationDueDate": "2021-09-28T15:00:00.000Z", + "paymentOpenDate": "2021-09-30T15:00:00.000Z", + "paymentDueDate": "2021-10-05T15:00:00.000Z", + "applicationID": "ES_2253", + "tickets": [] + }, + { + "name": "アンジュルム 上國料萌衣&笠原桃奈バースデーイベント2021", + "applicationStartDate": "2021-09-13T15:00:00.000Z", + "applicationDueDate": "2021-09-27T15:00:00.000Z", + "paymentOpenDate": "2021-09-30T15:00:00.000Z", + "paymentDueDate": "2021-10-05T15:00:00.000Z", + "applicationID": "ES_2250", + "tickets": [] + }, + { + "name": "アンジュルム コンサート2021 「桃源郷 ~笠原桃奈 卒業スペシャル~」", + "applicationStartDate": "2021-09-12T15:00:00.000Z", + "applicationDueDate": "2021-09-23T15:00:00.000Z", + "paymentOpenDate": "2021-09-29T15:00:00.000Z", + "paymentDueDate": "2021-10-03T15:00:00.000Z", + "applicationID": "ES_2249", + "tickets": [] + }, + { + "name": "演劇女子部「図書館物語~3つのブックマーク~」", + "applicationStartDate": "2021-09-12T15:00:00.000Z", + "applicationDueDate": "2021-09-21T15:00:00.000Z", + "paymentOpenDate": "2021-09-27T15:00:00.000Z", + "paymentDueDate": "2021-10-02T15:00:00.000Z", + "applicationID": "ES_2247", + "tickets": [] + }, + { + "name": "アンジュルム 笠原桃奈バースデーイベント2021", + "applicationStartDate": "2021-09-09T15:00:00.000Z", + "applicationDueDate": "2021-09-27T15:00:00.000Z", + "paymentOpenDate": "2021-09-29T15:00:00.000Z", + "paymentDueDate": "2021-10-05T15:00:00.000Z", + "applicationID": "ES_2246", + "tickets": [] + }, + { + "name": "BEYOOOOONDS/雨ノ森 川海 岡村美波バースデーイベント2021", + "applicationStartDate": "2021-09-09T15:00:00.000Z", + "applicationDueDate": "2021-09-26T15:00:00.000Z", + "paymentOpenDate": "2021-09-28T15:00:00.000Z", + "paymentDueDate": "2021-10-03T15:00:00.000Z", + "applicationID": "ES_2245", + "tickets": [] + }, + { + "name": "【当日券予約】ENPLEX × Hello! Project 名古屋定期イベント「ハロプロ研修生イベント in 名古屋」", + "applicationStartDate": "2021-09-08T15:00:00.000Z", + "applicationDueDate": "2021-09-12T15:00:00.000Z", + "paymentOpenDate": "2021-09-14T15:00:00.000Z", + "paymentDueDate": "2021-09-20T15:00:00.000Z", + "applicationID": "ES_2244", + "tickets": [] + }, + { + "name": "BEYOOOOONDS結成記念スペシャルライブ2021 ~ポップステップ付点音符.~", + "applicationStartDate": "2021-09-07T15:00:00.000Z", + "applicationDueDate": "2021-09-22T15:00:00.000Z", + "paymentOpenDate": "2021-09-26T15:00:00.000Z", + "paymentDueDate": "2021-10-02T15:00:00.000Z", + "applicationID": "ES_2242", + "tickets": [] + } +] diff --git a/expo/features/upfc/scraper/testdata/valid-available-applications.html b/expo/features/upfc/scraper/testdata/valid-available-applications.html new file mode 100644 index 00000000..15efbbab --- /dev/null +++ b/expo/features/upfc/scraper/testdata/valid-available-applications.html @@ -0,0 +1,1004 @@ + + + + + + + + + +Hello! Project + + + + +
+ +
+ + +
+ +
+ + +
+ +

チケット/イベント受付

+
+ +
+ +
+
    +
  1. お申し込みまでの流れ(先行受付分)
  2. +
  3. コンビニでのお支払い方法
  4. +
+

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hello! Project + + + + + +
+ +
+ + +
+ +
+ + +
+ + +

チケット/イベント受付(先行受付)

+
+
+

先行受付 受付&確認

+

ファンクラブ会員専用WEBサイトにてお知らせしている公演のチケット先行受付

+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + + + + + +

【NEXT先行】鈴木愛理 LIVE 2021~26/27~ @ 大阪・名古屋 お申し込み受付

+
+ 【NEXT先行】鈴木愛理 LIVE 2021~26/27~ @ 大阪・名古屋
+ + 受付期間  :2021年09月16日(木) 16時~2021年09月22日(水) 17時まで
+ 受付確認期間:2021年09月16日(木) 16時~2021年09月22日(水) 17時まで
+ + 当落発表期間:2021年09月24日(金) 18時~2021年09月30日(木) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。
+ご当選された場合、振込用紙の発送はございません。
+抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。
+(郵便局でお支払いされた場合は返金となりますので、ご注意ください。)

+

+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

ENPLEX × Hello! Project 名古屋定期イベント「アンジュルム 竹内朱莉 ‶竹を割ったような″イベント in 名古屋」 お申し込み受付

+
+ ENPLEX × Hello! Project 名古屋定期イベント「アンジュルム 竹内朱莉 ‶竹を割ったような″イベント in 名古屋」
+ + 受付期間  :2021年09月16日(木) 17時~2021年09月28日(火) 12時まで
+ 受付確認期間:2021年09月16日(木) 17時~2021年09月28日(火) 12時まで
+ + 当落発表期間:2021年09月30日(木) 16時~2021年10月06日(水) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。ご当選された場合、振込用紙の発送はございません。抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。 + +
+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

【NEXT先行】工藤遥バースデーイベント2021 ~22nd Best day ever~きょうやすSP お申し込み受付

+
+ 【NEXT先行】工藤遥バースデーイベント2021 ~22nd Best day ever~きょうやすSP
+ + 受付期間  :2021年09月16日(木) 16時~2021年09月24日(金) 17時まで
+ 受付確認期間:2021年09月16日(木) 16時~2021年09月24日(金) 17時まで
+ + 当落発表期間:2021年09月27日(月) 16時~2021年10月03日(日) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承下さい。
+ご当選された場合、振込用紙の発送はございません。
+抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払下さい。
+(郵便局でお支払いされた場合は返金となりますので、ご注意下さい。)


+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

【NEXT先行】宮崎由加ファンクラブイベント2021~Halloween yukanya~ お申し込み受付

+
+ 【NEXT先行】宮崎由加ファンクラブイベント2021~Halloween yukanya~
+ + 受付期間  :2021年09月15日(水) 16時~2021年09月22日(水) 17時まで
+ 受付確認期間:2021年09月15日(水) 16時~2021年09月22日(水) 17時まで
+ + 当落発表期間:2021年09月24日(金) 16時~2021年09月30日(木) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承下さい。
+ご当選された場合、振込用紙の発送はございません。
+抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払下さい。
+(郵便局でお支払いされた場合は返金となりますので、ご注意下さい。)


+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

【2次受付】M-line Special 2021~Make a Wish!~【10月公演】 お申し込み受付

+
+ 【2次受付】M-line Special 2021~Make a Wish!~【10月公演】
+ + 受付期間  :2021年09月14日(火) 16時~2021年09月21日(火) 10時まで
+ 受付確認期間:2021年09月14日(火) 16時~2021年09月21日(火) 10時まで
+ + 当落発表期間:2021年09月21日(火) 18時~2021年09月26日(日) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。
+ご当選された場合、振込用紙の発送はございません。
+抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。
+(郵便局でお支払いされた場合は返金となりますので、ご注意ください。)

+

+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

Juice=Juice新メンバー 有澤一華・入江里咲・江端妃咲FCイベント2021 お申し込み受付

+
+ Juice=Juice新メンバー 有澤一華・入江里咲・江端妃咲FCイベント2021
+ + 受付期間  :2021年09月15日(水) 18時~2021年09月29日(水) 23時まで
+ 受付確認期間:2021年09月15日(水) 18時~2021年09月29日(水) 23時まで
+ + 当落発表期間:2021年10月01日(金) 16時~2021年10月06日(水) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。ご当選された場合、振込用紙の発送はございません。抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。 +
+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

アンジュルム 上國料萌衣&笠原桃奈バースデーイベント2021 お申し込み受付

+
+ アンジュルム 上國料萌衣&笠原桃奈バースデーイベント2021
+ + 受付期間  :2021年09月14日(火) 18時~2021年09月28日(火) 12時まで
+ 受付確認期間:2021年09月14日(火) 18時~2021年09月28日(火) 12時まで
+ + 当落発表期間:2021年10月01日(金) 16時~2021年10月06日(水) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。ご当選された場合、振込用紙の発送はございません。抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。 +
+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

アンジュルム コンサート2021 「桃源郷 ~笠原桃奈 卒業スペシャル~」 お申し込み受付

+
+ アンジュルム コンサート2021 「桃源郷 ~笠原桃奈 卒業スペシャル~」
+ + 受付期間  :2021年09月13日(月) 17時~2021年09月24日(金) 17時まで
+ 受付確認期間:2021年09月13日(月) 17時~2021年09月24日(金) 17時まで
+ + 当落発表期間:2021年09月30日(木) 17時~2021年10月04日(月) 23時まで
+ +
+

+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

演劇女子部「図書館物語~3つのブックマーク~」 お申し込み受付

+
+ 演劇女子部「図書館物語~3つのブックマーク~」
+ + 受付期間  :2021年09月13日(月) 12時~2021年09月22日(水) 17時まで
+ 受付確認期間:2021年09月13日(月) 12時~2021年09月22日(水) 17時まで
+ + 当落発表期間:2021年09月28日(火) 17時~2021年10月03日(日) 23時まで
+ +
+

+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

アンジュルム 笠原桃奈バースデーイベント2021 お申し込み受付

+
+ アンジュルム 笠原桃奈バースデーイベント2021
+ + 受付期間  :2021年09月10日(金) 18時~2021年09月28日(火) 12時まで
+ 受付確認期間:2021年09月10日(金) 18時~2021年09月28日(火) 12時まで
+ + 当落発表期間:2021年09月30日(木) 16時~2021年10月06日(水) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。ご当選された場合、振込用紙の発送はございません。抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。 +
+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

BEYOOOOONDS/雨ノ森 川海 岡村美波バースデーイベント2021 お申し込み受付

+
+ BEYOOOOONDS/雨ノ森 川海 岡村美波バースデーイベント2021
+ + 受付期間  :2021年09月10日(金) 18時~2021年09月27日(月) 12時まで
+ 受付確認期間:2021年09月10日(金) 18時~2021年09月27日(月) 12時まで
+ + 当落発表期間:2021年09月29日(水) 16時~2021年10月04日(月) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。ご当選された場合、振込用紙の発送はございません。抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。 +
+
+ お申し込み受付
+
+
+
+
+ + + + + + + +

【当日券予約】ENPLEX × Hello! Project 名古屋定期イベント「ハロプロ研修生イベント in 名古屋」 当選・落選確認

+
+ 【当日券予約】ENPLEX × Hello! Project 名古屋定期イベント「ハロプロ研修生イベント in 名古屋」
+ + 受付期間  :2021年09月09日(木) 17時~2021年09月13日(月) 17時まで
+ 受付確認期間:2021年09月09日(木) 17時~2021年09月13日(月) 17時まで
+ + 当落発表期間:2021年09月15日(水) 16時~2021年09月21日(火) 20時まで
+ +
+

+
+ 当選・落選確認
+
+
+
+
+ + + + + + + +

BEYOOOOONDS結成記念スペシャルライブ2021 ~ポップステップ付点音符.~ お申し込み受付

+
+ BEYOOOOONDS結成記念スペシャルライブ2021 ~ポップステップ付点音符.~
+ + 受付期間  :2021年09月08日(水) 18時~2021年09月23日(木) 23時まで
+ 受付確認期間:2021年09月08日(水) 18時~2021年09月23日(木) 23時まで
+ + 当落発表期間:2021年09月27日(月) 16時~2021年10月03日(日) 23時まで
+ +
+
※お支払い方法はコンビニ支払いのみとなりますので、予めご了承ください。ご当選された場合、振込用紙の発送はございません。抽選結果確認期間中に、当落発表画面にてコンビニを選択し、ご指定のコンビニにてお支払ください。 +
+
+ お申し込み受付
+
+
+
+
+
+
+
+
+ + + +
+ + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + + + + +
+ + +
現在、先々行の受付はおこなっておりません。

+
+ + + + + + +
+ + + + + + + + diff --git a/expo/features/upfc/scraper/testdata/valid-no-event.html b/expo/features/upfc/scraper/testdata/valid-no-event.html new file mode 100644 index 00000000..56f4356d --- /dev/null +++ b/expo/features/upfc/scraper/testdata/valid-no-event.html @@ -0,0 +1,149 @@ + + + + + + + + + +Hello! Project + + + + +
+ +
+ + +
+ +
+ + +
+ +

チケット/イベント受付(先々行受付)

+
+ +
+ + +
+
+ +
+ + + 現在、受付しておりません。


+
+
+ +

+ +
+ +

+ +
+
+
+
+
+ + + +
+ + + + diff --git a/expo/features/upfc/scraper/testdata/valid-redirect.html b/expo/features/upfc/scraper/testdata/valid-redirect.html new file mode 100644 index 00000000..06dfa587 --- /dev/null +++ b/expo/features/upfc/scraper/testdata/valid-redirect.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/expo/features/upfc/scraper/testdata/valid-tickets-page.expected.json b/expo/features/upfc/scraper/testdata/valid-tickets-page.expected.json new file mode 100644 index 00000000..6f4bbccf --- /dev/null +++ b/expo/features/upfc/scraper/testdata/valid-tickets-page.expected.json @@ -0,0 +1,260 @@ +[ + { + "name": "モーニング娘。’20 小田さくらバースデーイベント ~さくらのしらべ9~", + "tickets": [ + { + "venue": "東京都 メルパルクホール", + "openAt": "2020-03-24T09:15:00.000Z", + "startAt": "2020-03-24T10:15:00.000Z", + "status": "申込済", + "num": 1 + } + ] + }, + { + "name": "こぶしファクトリー 和田桜子バースデーイベント2020", + "tickets": [ + { + "venue": "東京都 TOKYO FM HALL", + "openAt": "2020-03-09T08:30:00.000Z", + "startAt": "2020-03-09T09:00:00.000Z", + "status": "入金忘", + "num": 1 + }, + { + "venue": "東京都 TOKYO FM HALL", + "openAt": "2020-03-09T10:15:00.000Z", + "startAt": "2020-03-09T10:45:00.000Z", + "status": "落選", + "num": 1 + } + ] + }, + { + "name": "モーニング娘。’20 ディナーショー 「Happy Night」", + "tickets": [ + { + "venue": "愛知県 名古屋観光ホテル「那古の間」", + "openAt": "2020-04-05T02:30:00.000Z", + "startAt": "2020-04-05T03:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "愛知県 名古屋観光ホテル「那古の間」", + "openAt": "2020-04-05T07:30:00.000Z", + "startAt": "2020-04-05T08:30:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project ひなフェス 2020 ~被災地復興支援・東北を元気に!~", + "tickets": [ + { + "venue": "東京都 明治神宮会館", + "openAt": "2020-03-22T02:00:00.000Z", + "startAt": "2020-03-22T02:45:00.000Z", + "status": "落選", + "num": 2 + }, + { + "venue": "東京都 明治神宮会館", + "openAt": "2020-03-22T05:00:00.000Z", + "startAt": "2020-03-22T05:45:00.000Z", + "status": "入金済", + "num": 2 + } + ] + }, + { + "name": "こぶしファクトリー ライブ2020 ~The Final Ring!~", + "tickets": [ + { + "venue": "東京都 TOKYO DOME CITY HALL", + "openAt": "2020-03-30T08:30:00.000Z", + "startAt": "2020-03-30T09:30:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "BEYOOOOONDS 1st LIVE TOUR 2020~ポップ!ステップ!全音符!!~", + "tickets": [ + { + "venue": "東京都 吉祥寺CLUB SEATA", + "openAt": "2020-04-04T05:30:00.000Z", + "startAt": "2020-04-04T06:00:00.000Z", + "status": "落選", + "num": 2 + }, + { + "venue": "東京都 吉祥寺CLUB SEATA", + "openAt": "2020-04-04T08:30:00.000Z", + "startAt": "2020-04-04T09:00:00.000Z", + "status": "入金済", + "num": 2 + } + ] + }, + { + "name": "モーニング娘。’20 横山玲奈バースデーイベント", + "tickets": [ + { + "venue": "東京都 山野ホール", + "openAt": "2020-02-25T07:30:00.000Z", + "startAt": "2020-02-25T08:15:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 山野ホール", + "openAt": "2020-02-25T10:00:00.000Z", + "startAt": "2020-02-25T10:45:00.000Z", + "status": "入金済", + "num": 2 + } + ] + }, + { + "name": "モーニング娘。'20コンサートツアー春 (タイトル未定)", + "tickets": [ + { + "venue": "東京都 オリンパスホール八王子", + "openAt": "2020-03-14T05:00:00.000Z", + "startAt": "2020-03-14T06:00:00.000Z", + "status": "落選", + "num": 1 + }, + { + "venue": "東京都 オリンパスホール八王子", + "openAt": "2020-03-14T08:30:00.000Z", + "startAt": "2020-03-14T09:30:00.000Z", + "status": "落選", + "num": 1 + }, + { + "venue": "東京都 オリンパスホール八王子", + "openAt": "2020-03-15T04:00:00.000Z", + "startAt": "2020-03-15T05:00:00.000Z", + "status": "落選", + "num": 1 + }, + { + "venue": "東京都 オリンパスホール八王子", + "openAt": "2020-03-15T07:30:00.000Z", + "startAt": "2020-03-15T08:30:00.000Z", + "status": "落選", + "num": 1 + }, + { + "venue": "愛知県 名古屋国際会議場 センチュリーホール", + "openAt": "2020-05-04T05:00:00.000Z", + "startAt": "2020-05-04T06:00:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "愛知県 名古屋国際会議場 センチュリーホール", + "openAt": "2020-05-04T08:30:00.000Z", + "startAt": "2020-05-04T09:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザ", + "openAt": "2020-05-06T04:30:00.000Z", + "startAt": "2020-05-06T05:30:00.000Z", + "status": "落選", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザ", + "openAt": "2020-05-06T08:00:00.000Z", + "startAt": "2020-05-06T09:00:00.000Z", + "status": "落選", + "num": 1 + }, + { + "venue": "長野県 ホクト文化ホール(長野県県民文化会館)大ホール", + "openAt": "2020-05-30T05:00:00.000Z", + "startAt": "2020-05-30T06:00:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "長野県 ホクト文化ホール(長野県県民文化会館)大ホール", + "openAt": "2020-05-30T08:30:00.000Z", + "startAt": "2020-05-30T09:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "山梨県 YCC県民文化ホール(山梨県立県民文化ホール) 大ホール", + "openAt": "2020-05-31T04:30:00.000Z", + "startAt": "2020-05-31T05:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "山梨県 YCC県民文化ホール(山梨県立県民文化ホール) 大ホール", + "openAt": "2020-05-31T08:00:00.000Z", + "startAt": "2020-05-31T09:00:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project 2020 Winter HELLO! PROJECT IS [     ] ~side A~/~side B~", + "tickets": [ + { + "venue": "東京都 中野サンプラザ", + "openAt": "2020-01-11T04:30:00.000Z", + "startAt": "2020-01-11T05:30:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "東京都 中野サンプラザ", + "openAt": "2020-01-11T08:00:00.000Z", + "startAt": "2020-01-11T09:00:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "Hello! Project 2020 Summer COVERS ~The Ballad~ 先々行受付 (ハロプロ2020Summer愛知 先々行 掲載分)", + "tickets": [ + { + "venue": "愛知県 日本特殊陶業市民会館 フォレストホール", + "openAt": "2020-08-29T04:45:00.000Z", + "startAt": "2020-08-29T06:15:00.000Z", + "status": "入金済", + "num": 1 + }, + { + "venue": "愛知県 日本特殊陶業市民会館 フォレストホール", + "openAt": "2020-08-29T08:30:00.000Z", + "startAt": "2020-08-29T10:00:00.000Z", + "status": "入金済", + "num": 1 + } + ] + }, + { + "name": "モーニング娘。’20 小田さくらバースデーイベント ~さくらのしらべ9~ 先々行受付 (小田さくらBDイベント2020 掲載分)", + "tickets": [ + { + "venue": "東京都 コットンクラブ", + "openAt": "2020-07-28T07:30:00.000Z", + "startAt": "2020-07-28T08:00:00.000Z", + "status": "入金済", + "num": 1 + } + ] + } +] diff --git a/expo/features/upfc/scraper/testdata/valid-tickets-page.html b/expo/features/upfc/scraper/testdata/valid-tickets-page.html new file mode 100644 index 00000000..c47496d2 --- /dev/null +++ b/expo/features/upfc/scraper/testdata/valid-tickets-page.html @@ -0,0 +1,1070 @@ + + + + + マイページ|ハロープロジェクトオフィシャルファンクラブサイト + + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +
+

マイページMY PAGE

+
+ + + +
※各種入金状況につきましては反映まで数日かかる場合がございます。
+ + + +
+ チケット申込状況 +
+ + +
+ +
DM掲載分
+ + + +
WEB掲載分
+ + + +
+
+ ■ モーニング娘。’20 小田さくらバースデーイベント ~さくらのしらべ9~
+ +
+ + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2020/03 /24(火) + 東京都
+ メルパルクホール
+ 開場18:15
開演19:15
+ 一般席
+ 1枚 +
+ 申込済 + 支払方法:コンビニ
+
+
+ +
+
+ + + + + +
+
+ ■ こぶしファクトリー 和田桜子バースデーイベント2020
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2020/03 /09(月) + 東京都
+ TOKYO FM HALL
+ 開場17:30
開演18:00
+ 一般席
+ 1枚 +
+ 当選
(支払)
+ 支払方法:コンビニ
+
+
+ 公演番号
+ 02 +
+ 2020/03 /09(月) + 東京都
+ TOKYO FM HALL
+ 開場19:15
開演19:45
+ 一般席
+ 1枚 +
+ 落選 + 支払方法:コンビニ
+
+
+ +
+
+ + + + + +
+
+ ■ モーニング娘。’20 ディナーショー 「Happy Night」
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 03 +
+ 2020/04 /05(日) + 愛知県
+ 名古屋観光ホテル「那古の間」
+ 受付開始11:30
食事開始12:30
ショー開演13:30
+ 全席指定
+ 1枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2020/02/07(金)
+
+ 公演番号
+ 04 +
+ 2020/04 /05(日) + 愛知県
+ 名古屋観光ホテル「那古の間」
+ 受付開始16:30
食事開始17:30
ショー開演18:30
+ 全席指定
+ 1枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2020/02/07(金)
+
+ +
+
+ + + + + +
+
+ ■ Hello! Project ひなフェス 2020 ~被災地復興支援・東北を元気に!~
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 05 +
+ 2020/03 /22(日) + 東京都
+ 明治神宮会館
+ 開場11:00
開演11:45
+ 一般席
+ 2枚 +
+ 落選 + 支払方法:コンビニ
+
+
+ 公演番号
+ 06 +
+ 2020/03 /22(日) + 東京都
+ 明治神宮会館
+ 開場14:00
開演14:45
+ 一般席
+ 2枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2020/02/07(金)
+
+ +
+
+ + + + + +
+
+ ■ こぶしファクトリー ライブ2020 ~The Final Ring!~
+ +
+ + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2020/03 /30(月) + 東京都
+ TOKYO DOME CITY HALL
+ 開場17:30
開演18:30
+ 一般席
+ 1枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2020/02/07(金)
+
+ +
+
+ + + + + +
+
+ ■ BEYOOOOONDS 1st LIVE TOUR 2020~ポップ!ステップ!全音符!!~
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 03 +
+ 2020/04 /04(土) + 東京都
+ 吉祥寺CLUB SEATA
+ 開場14:30
開演15:00
+ 全自由
+ 2枚 +
+ 落選 + 支払方法:コンビニ
+
+
+ 公演番号
+ 04 +
+ 2020/04 /04(土) + 東京都
+ 吉祥寺CLUB SEATA
+ 開場17:30
開演18:00
+ 全自由
+ 2枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2020/01/29(水)
+
+ +
+
+ + + + + +
+
+ ■ モーニング娘。’20 横山玲奈バースデーイベント
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2020/02 /25(火) + 東京都
+ 山野ホール
+ 開場16:30
開演17:15
+ 一般席
+ 1枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2020/01/29(水)
+
+ 公演番号
+ 02 +
+ 2020/02 /25(火) + 東京都
+ 山野ホール
+ 開場19:00
開演19:45
+ 一般席
+ 2枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2020/01/29(水)
+
+ +
+
+ + + + + +
+
+ ■ モーニング娘。'20コンサートツアー春 (タイトル未定)
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2020/03 /14(土) + 東京都
+ オリンパスホール八王子
+ 開場14:00
開演15:00
+ 一般席
+ 1枚 +
+ 落選 + 支払方法:コンビニ
+
+
+ 公演番号
+ 02 +
+ 2020/03 /14(土) + 東京都
+ オリンパスホール八王子
+ 開場17:30
開演18:30
+ 一般席
+ 1枚 +
+ 落選 + 支払方法:コンビニ
+
+
+ 公演番号
+ 03 +
+ 2020/03 /15(日) + 東京都
+ オリンパスホール八王子
+ 開場13:00
開演14:00
+ 一般席
+ 1枚 +
+ 落選 + 支払方法:コンビニ
+
+
+ 公演番号
+ 04 +
+ 2020/03 /15(日) + 東京都
+ オリンパスホール八王子
+ 開場16:30
開演17:30
+ 一般席
+ 1枚 +
+ 落選 + 支払方法:コンビニ
+
+
+ 公演番号
+ 23 +
+ 2020/05 /04(月) + 愛知県
+ 名古屋国際会議場 センチュリーホール
+ 開場14:00
開演15:00
+ 一般席
+ 1枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2020/01/16(木)
+
+ 公演番号
+ 24 +
+ 2020/05 /04(月) + 愛知県
+ 名古屋国際会議場 センチュリーホール
+ 開場17:30
開演18:30
+ 一般席
+ 1枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2020/01/16(木)
+
+ 公演番号
+ 25 +
+ 2020/05 /06(水) + 東京都
+ 中野サンプラザ
+ 開場13:30
開演14:30
+ 一般席
+ 1枚 +
+ 落選 + 支払方法:コンビニ
+
+
+ 公演番号
+ 26 +
+ 2020/05 /06(水) + 東京都
+ 中野サンプラザ
+ 開場17:00
開演18:00
+ 一般席
+ 1枚 +
+ 落選 + 支払方法:コンビニ
+
+
+ 公演番号
+ 38 +
+ 2020/05 /30(土) + 長野県
+ ホクト文化ホール(長野県県民文化会館)大ホール
+ 開場14:00
開演15:00
+ 一般席
+ 1枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2020/01/16(木)
+
+ 公演番号
+ 39 +
+ 2020/05 /30(土) + 長野県
+ ホクト文化ホール(長野県県民文化会館)大ホール
+ 開場17:30
開演18:30
+ 一般席
+ 1枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2020/01/16(木)
+
+ 公演番号
+ 40 +
+ 2020/05 /31(日) + 山梨県
+ YCC県民文化ホール(山梨県立県民文化ホール) 大ホール
+ 開場13:30
開演14:30
+ 一般席
+ 1枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2020/01/16(木)
+
+ 公演番号
+ 41 +
+ 2020/05 /31(日) + 山梨県
+ YCC県民文化ホール(山梨県立県民文化ホール) 大ホール
+ 開場17:00
開演18:00
+ 一般席
+ 1枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2020/01/16(木)
+
+ +
+
+ + + + + +
+
+ ■ Hello! Project 2020 Winter HELLO! PROJECT IS [     ] ~side A~/~side B~
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 08 +
+ 2020/01 /11(土) + 東京都
+ 中野サンプラザ
+ 開場13:30
開演14:30
公演パターンB
+ 一般席
+ 1枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2019/11/14(木)
+ チケット発送日
2019/12/20
+ 公演番号
+ 09 +
+ 2020/01 /11(土) + 東京都
+ 中野サンプラザ
+ 開場17:00
開演18:00
公演パターンA
+ 一般席
+ 1枚 +
+ 当選
(入金済)
+ 支払方法:コンビニ
+ 入金日:2019/11/14(木)
+ チケット発送日
2019/12/20
+ +
+
+ +
先々行受付
+ + +
+
+ ■ Hello! Project 2020 Summer COVERS ~The Ballad~ 先々行受付 (ハロプロ2020Summer愛知 先々行 掲載分)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ 公演番号
+ 30 +
+ 2020/08 /29(土) + 愛知県
+ 日本特殊陶業市民会館 フォレストホール
+ 開場 13:45
+ 開演 15:15
+ 出演 Bチーム
+ 着席指定席 / 1 枚 ¥5,000
+ 申込済 + 支払方法:カード
入金日:2020/07/18(土)
+ +
+ 公演番号
+ 31 +
+ 2020/08 /29(土) + 愛知県
+ 日本特殊陶業市民会館 フォレストホール
+ 開場 17:30
+ 開演 19:00
+ 出演 Cチーム
+ 着席指定席 / 1 枚 ¥5,000
+ 申込済 + 支払方法:カード
入金日:2020/07/18(土)
+ +
+ +
+
+ + + + +
+
+ ■ モーニング娘。’20 小田さくらバースデーイベント ~さくらのしらべ9~ 先々行受付 (小田さくらBDイベント2020 掲載分)
+
+ + + + + + + + + + + + +
+ 公演番号
+ 01 +
+ 2020/07 /28(火) + 東京都
+ コットンクラブ
+ 開場 16:30
+ 開演 17:00
+
+ 一般席 / 1 枚 ¥5,200
+ 当選 + 支払方法:カード
入金日:2020/07/07(火)
+ +
+ +
+
+ + + +
+ +
+
+ +
+ + + +
+ + + diff --git a/expo/features/upfc/scraper/types.ts b/expo/features/upfc/scraper/types.ts new file mode 100644 index 00000000..ab1ec301 --- /dev/null +++ b/expo/features/upfc/scraper/types.ts @@ -0,0 +1,41 @@ +export const ErrAuthentication = new Error('failed to authenticate'); +export const ErrNoCredential = new Error('no credential is set'); +export const ErrInvalidStatusCode = new Error('up-fc.jp returned non 200 response'); + +export type EventTicket = { + venue: string; + status: TicketStatus; + num: number; +} & EventDateTime; + +export type EventDateTime = { + openAt?: Date; + startAt: Date; +}; + +export type EventApplication = { + name: string; + applicationID?: string | null; + applicationStartDate?: Date; + applicationDueDate?: Date; + paymentOpenDate?: Date; + paymentDueDate?: Date; +}; + +export type EventApplicationTickets = { + tickets: Array; +} & EventApplication; + +export type TicketStatus = '申込済' | '入金待' | '入金済' | '落選' | '入金忘' | '不明'; + +export interface Scraper { + authenticate(username: string, password: string): Promise; + getEventApplications(): Promise>; +} + +export interface Fetcher { + postCredential(username: string, password: string): Promise; + fetchEventApplicationsHtml(): Promise; + fetchExecEventApplicationsHtml(): Promise; + fetchTicketsHtml(): Promise; +} diff --git a/expo/features/upfc/settings/UPFCSettings.ts b/expo/features/upfc/settings/UPFCSettings.ts new file mode 100644 index 00000000..08c9fe45 --- /dev/null +++ b/expo/features/upfc/settings/UPFCSettings.ts @@ -0,0 +1,25 @@ +import { SettingsStore, SecureStorage } from "@hpapp/system/kvs"; + +type UPFCConfig = { + username: string; + password: string; + calendarId?: string | null; + eventPrefix?: string | null; +}; + +const UPFCSettings = SettingsStore.register( + "hpapp.upfc.config", + new SecureStorage({ + keychainService: "hpapp.upfc.config", + }), + { + migrationFrom: SettingsStore.register( + "hpapp.settings.fanclub", + new SecureStorage({ + keychainService: "hpapp.settings.fanclub.credentials", + }) + ), + } +); + +export { UPFCSettings, UPFCConfig }; diff --git a/expo/features/upfc/settings/UPFCSettingsForm.tsx b/expo/features/upfc/settings/UPFCSettingsForm.tsx new file mode 100644 index 00000000..3070cfa1 --- /dev/null +++ b/expo/features/upfc/settings/UPFCSettingsForm.tsx @@ -0,0 +1,146 @@ +import { useCallback, useState } from "react"; +import { View, StyleSheet } from "react-native"; +import { Input, Button } from "@rneui/themed"; +import Toast from "react-native-root-toast"; +import { UPFCSettings } from "@hpapp/features/upfc/settings/UPFCSettings"; +import { + DemoScraper, + ErrAuthentication, + useScraper, +} from "@hpapp/features/upfc/scraper"; +import { t } from "@hpapp/system/i18n"; +import { Spacing } from "@hpapp/features/common/constants"; +import { useColor } from "@hpapp/contexts/settings/theme"; +import { useSettings } from "@hpapp/contexts/settings"; +import UPFCSettingsFormInputs from "@hpapp/features/upfc/settings/UPFCSettingsFormInputs"; +// import { useHomeUPFCModel } from "src/models/upfc/HomeUPFCProvider"; + +const getErrorMessage = (e: unknown) => { + if (e === null) { + return ""; + } + if (e === ErrAuthentication) { + return t("ErrAuthentication"); + } + return t("SomethingWrongWithUPFC"); +}; + +export default function UPFCSettingsForm() { + // const upfc = useHomeUPFCModel(); + const [successColor, succsesContrast] = useColor("success"); + const scraper = useScraper(false); + const [isSaving, setIsSaving] = useState(false); + const [lastError, setLastError] = useState(null); + const [config, setConfig] = useSettings(UPFCSettings); + const [username, setUsername] = useState(config?.username || ""); + const [password, setPassword] = useState(config?.password || ""); + const [calendarId, setCalendarId] = useState(config?.calendarId || ""); + const [eventPrefix, setEventPrefix] = useState(config?.eventPrefix || ""); + const handleOnClear = useCallback(async () => { + setUsername(""); + setPassword(""); + setCalendarId(""); + setEventPrefix(""); + setConfig(null); + // clear the cache + // await upfc.clearCache(); + // await upfc.reload(); + }, [setConfig, setUsername, setPassword, setCalendarId, setEventPrefix]); + const handleOnSave = useCallback(() => { + setLastError(null); + setIsSaving(true); + (async () => { + try { + if (username !== "" && password !== "") { + if (username !== DemoScraper.Username) { + await scraper.authenticate(username, password); + } + } + Toast.show(t("Saved successfully"), { + position: Toast.positions.BOTTOM, + duration: Toast.durations.SHORT, + textColor: succsesContrast, + backgroundColor: successColor, + }); + setConfig({ + username, + password, + calendarId, + eventPrefix, + }); + // upfc.reload(); + } catch (e) { + setLastError(e); + } + setIsSaving(false); + })(); + }, [setConfig, username, password, calendarId, eventPrefix]); + return ( + + + + + + + + ); +} + +const styles = StyleSheet.create({ + container: { + paddingLeft: Spacing.Small, + paddingRight: Spacing.Small, + }, + inputGroup: { + marginTop: Spacing.XSmall, + }, + label: { + paddingLeft: Spacing.Small, + paddingRight: Spacing.Small, + }, + input: {}, + calendar: { + marginLeft: Spacing.XXSmall, + }, + inputError: { + height: 0, // no need to show + }, + errorMessage: { + paddingLeft: Spacing.Small, + fontStyle: "italic", + }, + buttonGroup: { + marginTop: Spacing.Small, + width: "100%", + flexDirection: "row", + justifyContent: "space-evenly", + }, + button: { + flexGrow: 1, + paddingLeft: Spacing.Small, + paddingRight: Spacing.Small, + }, +}); diff --git a/expo/features/upfc/settings/UPFCSettingsFormInputs.tsx b/expo/features/upfc/settings/UPFCSettingsFormInputs.tsx new file mode 100644 index 00000000..ea5b4372 --- /dev/null +++ b/expo/features/upfc/settings/UPFCSettingsFormInputs.tsx @@ -0,0 +1,125 @@ +import { View, StyleSheet } from "react-native"; +import { Input } from "@rneui/themed"; +import { ErrAuthentication } from "@hpapp/features/upfc/scraper"; +import { t } from "@hpapp/system/i18n"; +import CalendarDropdown from "@hpapp/features/common/components/form/CalendarDropdown"; +import { Spacing } from "@hpapp/features/common/constants"; +import { useColor } from "@hpapp/contexts/settings/theme"; +import Text from "@hpapp/features/common/components/Text"; + +export type UPFCSettingsFormInputsProps = { + isSaving: boolean; + lastError: unknown | null; + username: string; + onChangeUsername: (s: string) => void; + password: string; + onChangePassword: (s: string) => void; + calendarId: string; + onChangeCalendarId: (s: string) => void; + eventPrefix: string; + onChangeEventPrefix: (s: string) => void; +}; + +export default function UPFCSettingsFormInputs({ + isSaving, + lastError, + username, + onChangeUsername, + password, + onChangePassword, + calendarId, + onChangeCalendarId, + eventPrefix, + onChangeEventPrefix, +}: UPFCSettingsFormInputsProps) { + const [errorColor] = useColor("error"); + return ( + <> + + {t("FC Member Number")} + + + + {t("FC Password")} + + + + {t("Sync Events to Calendar")} + { + onChangeCalendarId(calender?.id || ""); + }} + renderIfPermissionDenied={ + + {t("Permission is denied. Open Settings to allow access")} + + } + nullText={t("Do not sync")} + /> + + + {t("Event Prefix")} + + + + + {getErrorMessage(lastError)} + + + + ); +} + +const styles = StyleSheet.create({ + inputGroup: { + marginTop: Spacing.XSmall, + }, + label: { + paddingLeft: Spacing.Small, + paddingRight: Spacing.Small, + }, + input: {}, + inputError: { + height: 0, // no need to show + }, + errorMessage: { + paddingLeft: Spacing.Small, + fontStyle: "italic", + }, +}); + +const getErrorMessage = (e: unknown) => { + if (e === null) { + return ""; + } + if (e === ErrAuthentication) { + return t("ErrAuthentication"); + } + return t("SomethingWrongWithUPFC"); +}; diff --git a/expo/features/upfc/UPFCSettingsScreen.tsx b/expo/features/upfc/settings/UPFCSettingsScreen.tsx similarity index 89% rename from expo/features/upfc/UPFCSettingsScreen.tsx rename to expo/features/upfc/settings/UPFCSettingsScreen.tsx index c364405e..ae6b2ac9 100644 --- a/expo/features/upfc/UPFCSettingsScreen.tsx +++ b/expo/features/upfc/settings/UPFCSettingsScreen.tsx @@ -6,6 +6,7 @@ import { useScreenTitle, } from "@hpapp/features/root/protected/stack"; import ConsentGate from "@hpapp/features/policy/ConsentGate"; +import UPFCSettingsForm from "@hpapp/features/upfc/settings/UPFCSettingsForm"; export default defineScreen("/upfc/settings/", function UPFCSettingScreen() { useScreenTitle(t("FC Settings")); @@ -25,7 +26,7 @@ export default defineScreen("/upfc/settings/", function UPFCSettingScreen() { }} pass={userConfig!.consentOnUPFCDataPolicy || false} > - <> + ); diff --git a/expo/foundation/test_helper.ts b/expo/foundation/test_helper.ts new file mode 100644 index 00000000..cf877896 --- /dev/null +++ b/expo/foundation/test_helper.ts @@ -0,0 +1,16 @@ +import { readFile as readFileOrig } from "fs"; + +function readFile(path: string): Promise { + return new Promise((resolve) => { + readFileOrig(path, (err, data) => { + return err ? resolve("") : resolve(data.toString()); + }); + }); +} + +async function readFileAsJSON(path: string): Promise { + const json = await readFile(path); + return JSON.parse(json) as T; +} + +export { readFile, readFileAsJSON }; diff --git a/expo/package.json b/expo/package.json index 43eee1f5..5f5717f0 100644 --- a/expo/package.json +++ b/expo/package.json @@ -33,6 +33,7 @@ "@react-native-firebase/app": "^17.4.3", "@react-native-firebase/app-check": "^17.4.3", "@react-native-firebase/auth": "^17.4.3", + "@react-native-picker/picker": "2.4.8", "@react-navigation/bottom-tabs": "^6.5.7", "@react-navigation/native": "^6.1.6", "@react-navigation/native-stack": "^6.9.12", @@ -43,6 +44,7 @@ "expo-asset": "~8.9.1", "expo-auth-session": "~4.0.3", "expo-build-properties": "~0.6.0", + "expo-calendar": "~11.1.1", "expo-constants": "~14.2.1", "expo-dev-client": "~2.2.1", "expo-device": "~5.2.1", @@ -52,10 +54,13 @@ "expo-status-bar": "~1.4.4", "expo-updates": "~0.16.4", "i18n-js": "^4.3.2", + "jsdom-jscore-rn": "^0.1.8", "react": "18.2.0", "react-dom": "18.2.0", "react-native": "0.71.8", "react-native-pager-view": "^6.2.1", + "react-native-picker": "^4.3.7", + "react-native-root-toast": "^3.5.1", "react-native-safe-area-context": "4.5.0", "react-native-screens": "~3.20.0", "react-native-tab-view": "^3.5.2", diff --git a/expo/yarn.lock b/expo/yarn.lock index 0625ca2c..4fa45ab5 100644 --- a/expo/yarn.lock +++ b/expo/yarn.lock @@ -2240,6 +2240,11 @@ dependencies: plist "^3.0.5" +"@react-native-picker/picker@2.4.8": + version "2.4.8" + resolved "https://registry.yarnpkg.com/@react-native-picker/picker/-/picker-2.4.8.tgz#a1a21f3d6ecadedbc3f0b691a444ddd7baa081f8" + integrity sha512-5NQ5XPo1B03YNqKFrV6h9L3CQaHlB80wd4ETHUEABRP2iLh7FHLVObX2GfziD+K/VJb8G4KZcZ23NFBFP1f7bg== + "@react-native/assets@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@react-native/assets/-/assets-1.0.0.tgz#c6f9bf63d274bafc8e970628de24986b30a55c8e" @@ -4020,6 +4025,15 @@ depd@2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +deprecated-react-native-prop-types@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz#c10c6ee75ff2b6de94bb127f142b814e6e08d9ab" + integrity sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA== + dependencies: + "@react-native/normalize-color" "*" + invariant "*" + prop-types "*" + deprecated-react-native-prop-types@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-3.0.1.tgz#a275f84cd8519cd1665e8df3c99e9067d57a23ec" @@ -4063,6 +4077,24 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +domelementtype@1, domelementtype@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + domexception@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" @@ -4070,11 +4102,26 @@ domexception@^4.0.0: dependencies: webidl-conversions "^7.0.0" +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== + dependencies: + domelementtype "1" + domino@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.6.tgz#fe4ace4310526e5e7b9d12c7de01b7f485a57ffe" integrity sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ== +domutils@^1.5.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + dotenv@16.0.3: version "16.0.3" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07" @@ -4199,6 +4246,16 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" +entities@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + entities@^4.4.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" @@ -4318,6 +4375,11 @@ event-target-shim@^5.0.0, event-target-shim@^5.0.1: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== +eventemitter2@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-1.0.5.tgz#f983610517b1737c0b9dc643beca93893c04df18" + integrity sha512-EUFhWUYzqqBZlzBMI+dPU8rnKXfQZEUnitnccQuEIAnvWFHCpt3+4fts2+4dpxLtlsiseVXCMFg37KjYChSxpg== + exec-async@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/exec-async/-/exec-async-2.2.0.tgz#c7c5ad2eef3478d38390c6dd3acfe8af0efc8301" @@ -4423,6 +4485,11 @@ expo-build-properties@~0.6.0: ajv "^8.11.0" semver "^7.3.5" +expo-calendar@~11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/expo-calendar/-/expo-calendar-11.1.1.tgz#c790dce535dc97fb15982b54b1c59c46dfe21d8d" + integrity sha512-ErXERbhdzI7RhdEFF94p5+UljoMT6p+POf2eDmoBicg7RieM/6kHDUL75B0JzBFy9FS86RDDdsIHFf2gzl6qWw== + expo-constants@~14.2.0, expo-constants@~14.2.1: version "14.2.1" resolved "https://registry.yarnpkg.com/expo-constants/-/expo-constants-14.2.1.tgz#b5b6b8079d2082c31ccf2cbc7cf97a0e83c229c3" @@ -5224,6 +5291,19 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== +htmlparser2-without-node-native@^3.9.2: + version "3.9.2" + resolved "https://registry.yarnpkg.com/htmlparser2-without-node-native/-/htmlparser2-without-node-native-3.9.2.tgz#b3ed050d877d0ff3465969e339877b7f9f6631f6" + integrity sha512-+FplQXqmY5fRx6vCIp2P5urWaoBCpTNJMXnKP/6mNCcyb+AZWWJzA8D03peXfozlxDL+vpgLK5dJblqEgu8j6A== + dependencies: + domelementtype "^1.3.0" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + eventemitter2 "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.2" + http-call@^5.2.2: version "5.3.0" resolved "https://registry.yarnpkg.com/http-call/-/http-call-5.3.0.tgz#4ded815b13f423de176eb0942d69c43b25b148db" @@ -5364,7 +5444,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -6275,6 +6355,14 @@ jscodeshift@^0.13.1: temp "^0.8.4" write-file-atomic "^2.3.0" +jsdom-jscore-rn@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/jsdom-jscore-rn/-/jsdom-jscore-rn-0.1.8.tgz#b7acfa2bfafd5d1ab5d8813b62c536b81bcc639a" + integrity sha512-Sm0BCCQL3RRmJwztZa9B4QIOxgFOiu7vpsJjLsjG55HlRzOgUdmTOHrhV4SZkjXef5sBF+E8qKnrhsBUO7Gxjg== + dependencies: + htmlparser2-without-node-native "^3.9.2" + querystring "^0.2.0" + jsdom@^20.0.0: version "20.0.3" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-20.0.3.tgz#886a41ba1d4726f67a8858028c99489fed6ad4db" @@ -7750,7 +7838,7 @@ prompts@2.4.2, prompts@^2.0.1, prompts@^2.2.1, prompts@^2.3.2, prompts@^2.4.0: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@*: +prop-types@*, prop-types@^15.5.10: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -7835,6 +7923,11 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== +querystring@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" + integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== + querystringify@^2.1.1: version "2.2.0" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" @@ -7926,6 +8019,11 @@ react-native-pager-view@^6.2.1: resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-6.2.1.tgz#985d21bbb7d7bc012f4c142dedbb98ce4bdea104" integrity sha512-fZ8chez5J+w831nSnbtK8hwlCiMy1DgpFv8xG6ajXLsAI8uMkGvP554QDIDNlUoCuVwMf7OFyd32Y2Nm2Iaj9Q== +react-native-picker@^4.3.7: + version "4.3.7" + resolved "https://registry.yarnpkg.com/react-native-picker/-/react-native-picker-4.3.7.tgz#9842e8c62ff0d8b676e9514d9f9172413c0518a8" + integrity sha512-bqY0FOsgNe/svnlV7CTvDKjqca5iZr0E0h4gYO8LDh9alxGK7P6bTvqSx6VwDR144moHAG7dsKGrSH2r8bTx2Q== + react-native-ratings@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/react-native-ratings/-/react-native-ratings-8.1.0.tgz#3fa9ad29128dc3a88e59518ba151e61c59dd0647" @@ -7933,6 +8031,20 @@ react-native-ratings@^8.1.0: dependencies: lodash "^4.17.15" +react-native-root-siblings@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/react-native-root-siblings/-/react-native-root-siblings-4.1.1.tgz#b7742db7634a87f507eb99a5fd699c4f10c46ab0" + integrity sha512-sdmLElNs5PDWqmZmj4/aNH4anyxreaPm61c4ZkRiR8SO/GzLg6KjAbb0e17RmMdnBdD0AIQbS38h/l55YKN4ZA== + +react-native-root-toast@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/react-native-root-toast/-/react-native-root-toast-3.5.1.tgz#550520c77ee15c97ea6fb90151262ceb89cdcacc" + integrity sha512-zqsuec7Ugx2/9hR9BHqcmb3WWC/WBouqn2RYIpeTG+OpVvVfvr2UhWK4kLPJLk5/icZWl3xJrqiktPpbRpEA2A== + dependencies: + deprecated-react-native-prop-types "^2.3.0" + prop-types "^15.5.10" + react-native-root-siblings "^4.0.0" + react-native-safe-area-context@4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-4.5.0.tgz#9208313236e8f49e1920ac1e2a2c975f03aed284" @@ -8059,16 +8171,7 @@ react@18.2.0: dependencies: loose-envify "^1.1.0" -readable-stream@^3.4.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@~2.3.6: +readable-stream@^2.0.2, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -8081,6 +8184,15 @@ readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readline@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/readline/-/readline-1.3.0.tgz#c580d77ef2cfc8752b132498060dc9793a7ac01c"