iphone-xudale 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. package/.eslintrc.json +3 -0
  2. package/app/(pages)/options/page.tsx +720 -0
  3. package/app/(pages)/popup/page.tsx +166 -0
  4. package/app/(pages)/tips/page.tsx +40 -0
  5. package/app/components/DropListBox.tsx +157 -0
  6. package/app/components/SVGPlay.tsx +14 -0
  7. package/app/favicon.ico +0 -0
  8. package/app/globals.css +27 -0
  9. package/app/layout.tsx +15 -0
  10. package/app/page.tsx +3 -0
  11. package/app/scripts/content/checkoutSteps.ts +341 -0
  12. package/app/scripts/content/doFroApplePages.ts +206 -0
  13. package/app/scripts/content/getPageInitInfo.ts +49 -0
  14. package/app/scripts/content/getStoreCanPickInfo.ts +251 -0
  15. package/app/scripts/content/goOrderSteps.ts +179 -0
  16. package/app/scripts/content/index.ts +56 -0
  17. package/app/scripts/content/playSystemNotifacation.ts +39 -0
  18. package/app/scripts/content/sendSelfNotificatioin.ts +27 -0
  19. package/app/scripts/inject/index.ts +18 -0
  20. package/app/shared/constants.ts +236 -0
  21. package/app/shared/interface.ts +25 -0
  22. package/app/shared/location/city.json +1774 -0
  23. package/app/shared/location/county.json +17115 -0
  24. package/app/shared/location/province.json +94 -0
  25. package/app/shared/util.ts +93 -0
  26. package/buildAfter.js +86 -0
  27. package/bunBuild.ts +54 -0
  28. package/extension/content-script.js +7 -0
  29. package/extension/favicon.ico +0 -0
  30. package/extension/icons/icon128.png +0 -0
  31. package/extension/icons/icon16.png +0 -0
  32. package/extension/icons/icon19-disable.png +0 -0
  33. package/extension/icons/icon19.png +0 -0
  34. package/extension/icons/icon32.png +0 -0
  35. package/extension/icons/icon38.png +0 -0
  36. package/extension/icons/icon48.png +0 -0
  37. package/extension/inject-script.js +1 -0
  38. package/extension/manifest.json +38 -0
  39. package/extension/service-worker.js +62 -0
  40. package/extension.next.config.js +25 -0
  41. package/icon_generator.py +30 -0
  42. package/middleware.ts +21 -0
  43. package/next.config.js +15 -0
  44. package/package.json +67 -0
  45. package/postcss.config.js +6 -0
  46. package/public/assets/images/SCR-20230916-nbkz.png +0 -0
  47. package/public/assets/images/SCR-20230916-nbyv.png +0 -0
  48. package/public/assets/images/SCR-20230916-ncte.png +0 -0
  49. package/public/assets/images/SCR-20230916-ndgw.png +0 -0
  50. package/public/assets/images/SCR-20230916-ndks.png +0 -0
  51. package/public/assets/images/SCR-20230916-neaa.png +0 -0
  52. package/public/assets/images/SCR-20230916-neeq.jpeg +0 -0
  53. package/public/assets/images/SCR-20230916-nfkt.png +0 -0
  54. package/public/assets/images/SCR-20230919-ulfn.png +0 -0
  55. package/public/assets/images/SCR-20230919-ulzd.png +0 -0
  56. package/public/assets/images/SCR-20230919-uocr.png +0 -0
  57. package/public/icon_original.png +0 -0
  58. package/public/next.svg +1 -0
  59. package/public/vercel.svg +1 -0
  60. package/tailwind.config.ts +20 -0
  61. package/tsconfig.json +27 -0
  62. package/types/global.d.ts +19 -0
@@ -0,0 +1,166 @@
1
+ 'use client'
2
+ import { restoreFromStorage, saveToStorage } from '@/app/shared/util'
3
+ import { defaultiPhoneOrderConfig, storeKeys } from '@/app/shared/constants'
4
+ import { useEffect, useState } from 'react'
5
+ import { Match_URL } from '@/app/shared/constants'
6
+ import { IPHONEORDER_CONFIG } from '@/app/shared/interface'
7
+ import SVGPlay from '@/app/components/SVGPlay'
8
+
9
+ const Popup = () => {
10
+ const [orderEnabled, setOrderEnable] = useState<boolean>(false)
11
+ const [config, setConfig] = useState<IPHONEORDER_CONFIG>(defaultiPhoneOrderConfig)
12
+ // 异步获取enable状态
13
+ useEffect(() => {
14
+ const getOrderEnable = async () => {
15
+ const isEnabled = await restoreFromStorage(storeKeys.orderEnabled)
16
+ const config = await restoreFromStorage(storeKeys.orderConfig)
17
+ setOrderEnable(!!isEnabled)
18
+ setConfig(config as IPHONEORDER_CONFIG)
19
+ }
20
+ getOrderEnable()
21
+ }, [])
22
+
23
+ const handleOptionClick = () => {
24
+ if (typeof chrome !== 'undefined' && chrome?.runtime) {
25
+ chrome.runtime.openOptionsPage()
26
+ } else {
27
+ console.log(`please open in chrome`)
28
+ }
29
+ }
30
+ const handleConfirm = () => {
31
+ if (
32
+ !orderEnabled ||
33
+ (config?.lastName &&
34
+ config?.mobile &&
35
+ config?.firstName &&
36
+ config?.appleId &&
37
+ config?.last4code &&
38
+ config?.cityName &&
39
+ config?.districtName &&
40
+ config?.provinceName)
41
+ ) {
42
+ confirmAsync(orderEnabled)
43
+ } else {
44
+ setOrderEnable(false)
45
+ alert(`请先配置必要信息`)
46
+ }
47
+ }
48
+
49
+ const handleTestNotification = () => {
50
+ if (typeof chrome !== 'undefined' && chrome?.tabs) {
51
+ // @ts-ignore
52
+ chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
53
+ chrome.tabs.sendMessage(tabs[0].id, {
54
+ data: 'playSystemNotification',
55
+ voiceInfo: config?.voiceInfo || {},
56
+ })
57
+ })
58
+ chrome.runtime.sendMessage()
59
+ }
60
+
61
+ console.log(`chrome?.runtime`, chrome?.tabs)
62
+ }
63
+
64
+ return (
65
+ <div className="mx-auto mt-1 mb-2 w-[18rem] h-[15rem]">
66
+ <main className="flex w-fit flex-col items-center gap-2 justify-between py-3 px-2 mx-auto mb-2 mt-2">
67
+ <div className="flex w-full gap-3 justify-center py-1 mb-2 bg-white border-b border-solid border-slate-300">
68
+ <div
69
+ className={`flex w-40 h-9 ${'bg-indigo-600 cursor-pointer'} bg-opacity-90 border border-indigo-500 rounded-md my-2 items-center align-middle justify-center text-center min-w-min px-3 hover:shadow-md hover:bg-indigo-500`}
70
+ onClick={handleTestNotification}
71
+ >
72
+ <SVGPlay className="w-5 h-5 mr-2" />
73
+ 通知测试
74
+ </div>
75
+ </div>
76
+ <div className="flex flex-row gap-3 h-10 justify-between mb-2 px-4 py-6 rounded-xl bg-slate-100">
77
+ <div className="flex text-gray-600 items-center text-base font-bold">开启自动抢购</div>
78
+ <SelectItem
79
+ enabled={orderEnabled}
80
+ index={0}
81
+ callback={({ enabled }) => {
82
+ setOrderEnable(enabled)
83
+ }}
84
+ />
85
+ </div>
86
+ </main>
87
+ <div className="w-full flex flex-row justify-center text-center items-center gap-5 text-sm">
88
+ <div
89
+ className={`flex w-1/3 h-9 bg-white text-indigo-500 cursor-pointer bg-opacity-90 border-4 border-t-2 border-indigo-500 rounded-3xl my-2 items-center align-middle justify-center text-center min-w-min px-3 hover:shadow-md hover:border-t-[3px] hover:border-b-[3px]`}
90
+ onClick={handleOptionClick}
91
+ >
92
+ 配置
93
+ </div>
94
+ <div
95
+ className={`flex w-1/3 h-9 ${'bg-indigo-600 cursor-pointer'} bg-opacity-90 border border-indigo-500 rounded-3xl my-2 items-center align-middle justify-center text-center min-w-min px-3 hover:shadow-md hover:bg-indigo-500`}
96
+ onClick={handleConfirm}
97
+ >
98
+ 确认
99
+ </div>
100
+ </div>
101
+ </div>
102
+ )
103
+ }
104
+
105
+ export default Popup
106
+
107
+ interface ISelectItemProps {
108
+ enabled?: boolean
109
+ index: number
110
+ callback: ({ enabled }: { enabled: boolean }) => void
111
+ }
112
+ const SelectItem = ({ enabled, callback }: ISelectItemProps) => {
113
+ const handleToggle = () => {
114
+ callback({
115
+ enabled: !enabled,
116
+ })
117
+ }
118
+ return (
119
+ <div className="flex flex-row gap-6">
120
+ <div className="w-20 flex-col justify-center items-end gap-1.5 inline-flex">
121
+ {enabled ? (
122
+ <div
123
+ className="w-14 h-7 bg-indigo-600 bg-opacity-70 rounded-2xl py-0.5 px-[0.2rem] flex relative cursor-pointer ease-linear duration-500 shadow-indigo-500/50 shadow-md"
124
+ onClick={handleToggle}
125
+ >
126
+ <div className="w-6 h-6 bg-gray-100 rounded-full pt-1 pb-2 px-1 ease-linear duration-300 ml-[1.65rem]"></div>
127
+ </div>
128
+ ) : (
129
+ <div
130
+ className="w-14 h-7 bg-slate-400 bg-opacity-50 rounded-2xl py-0.5 px-[0.2rem] flex relative cursor-pointer ease-linear duration-500 shadow-slate-500/50 shadow-md"
131
+ onClick={handleToggle}
132
+ >
133
+ <div className="w-6 h-6 bg-gray-100 rounded-full pt-1 pb-2 px-1 ease-linear duration-300 ml-0"></div>
134
+ </div>
135
+ )}
136
+ </div>
137
+ </div>
138
+ )
139
+ }
140
+
141
+ interface ICondirmLoadProps {
142
+ callback?: (msg: string) => void
143
+ }
144
+ const confirmLoad = async ({ callback }: ICondirmLoadProps) => {
145
+ let msg = ``
146
+ if (typeof chrome === 'undefined' || !chrome?.tabs) {
147
+ msg = 'Please use as chrome extension'
148
+ callback && callback(msg)
149
+ return
150
+ }
151
+
152
+ const [tab] = await chrome.tabs.query({ active: true, currentWindow: true })
153
+ const tabUrl = (tab?.url || '').toLowerCase()
154
+ const urlObj = new URL(tabUrl)
155
+ const isInMatchUrl = urlObj.href.includes(Match_URL)
156
+
157
+ if (isInMatchUrl) {
158
+ chrome.tabs.reload(tab.id)
159
+ return
160
+ }
161
+ }
162
+
163
+ const confirmAsync = async (orderEnabled: boolean) => {
164
+ await saveToStorage(orderEnabled, storeKeys.orderEnabled)
165
+ window.close()
166
+ }
@@ -0,0 +1,40 @@
1
+ 'use client'
2
+ import { useEffect, useState } from 'react'
3
+ import { iframeMessagePass } from '@/app/shared/constants'
4
+
5
+ const Tips = () => {
6
+ const [fetchCount, setFetchCount] = useState(0)
7
+ const [beforeReload, setBeforeReload] = useState(50)
8
+ useEffect(() => {
9
+ window.addEventListener('message', function (event) {
10
+ if (event.data.action === iframeMessagePass.messageAction) {
11
+ setFetchCount(event.data.count)
12
+ setBeforeReload(event.data.beforeReload)
13
+ }
14
+ })
15
+ }, [])
16
+
17
+ const bgTransparent = `body{background: transparent}`
18
+ if (!fetchCount)
19
+ return (
20
+ <div>
21
+ <style>{bgTransparent}</style>
22
+ </div>
23
+ )
24
+ return (
25
+ <main className="flex w-52 h-fit flex-col text-gray-700 items-center gap-1 px-2 justify-between py-2 mx-auto rounded-lg bg-slate-100 text-base font-bold cursor-pointer shadow-slate-500/50 shadow-lg">
26
+ <style>{bgTransparent}</style>
27
+ <div className="flex flex-row gap-0 h-8 items-center justify-center py-2 ">
28
+ <div className=" ">
29
+ 当前正在重试:
30
+ <span className=" text-indigo-700">{fetchCount > 9 ? fetchCount : '0' + fetchCount}</span>次
31
+ </div>
32
+ </div>
33
+ <div className="flex flex-row h-8">
34
+ <span className="text-indigo-700">{beforeReload}</span>次之后将刷新页面
35
+ </div>
36
+ </main>
37
+ )
38
+ }
39
+
40
+ export default Tips
@@ -0,0 +1,157 @@
1
+ 'use client'
2
+ import { Fragment, useEffect, useState } from 'react'
3
+ import { Listbox, Transition } from '@headlessui/react'
4
+ import { CheckIcon, ChevronUpDownIcon } from '@heroicons/react/20/solid'
5
+ import { find as _find } from 'lodash'
6
+
7
+ type DropItem = {
8
+ id: number | string
9
+ name: string
10
+ icon?: string
11
+ } & Record<string, any>
12
+
13
+ interface IDropListBoxProps {
14
+ domID?: string
15
+ title?: string
16
+ itemList: Array<DropItem>
17
+ selectedIndex?: number
18
+
19
+ callback?: (item: DropItem) => void
20
+ }
21
+ export default function DropListBox({ domID, title, itemList, selectedIndex, callback }: IDropListBoxProps) {
22
+ const [selected, setSelected] = useState(itemList[selectedIndex || 0])
23
+
24
+ const handleSelect = (item: DropItem) => {
25
+ setSelected(item)
26
+ if (callback) callback(item)
27
+ }
28
+
29
+ // useEffect(() => {
30
+ // let newItem: DropItem
31
+ // if (selectedIndex !== undefined) {
32
+ // newItem = itemList[selectedIndex]
33
+ // } else {
34
+ // newItem = itemList[0]
35
+ // }
36
+ // setSelected(newItem)
37
+ // if (callback) callback(newItem)
38
+ // }, [itemList, selectedIndex])
39
+
40
+ // useEffect(() => {
41
+ // console.log(`selectedIndex`, selectedIndex)
42
+ // // 当之前的selected对象在新的itemList中存在时,不做处理
43
+ // if(!_find(itemList, _item=>{
44
+ // return _item.id == selected.id && _item.name == selected.name
45
+ // })){
46
+ // let newItem: DropItem
47
+ // if (selectedIndex !== undefined && itemList[selectedIndex]) {
48
+ // newItem = itemList[selectedIndex]
49
+ // }else{
50
+ // newItem = itemList[0]
51
+ // }
52
+ // setSelected(newItem)
53
+ // if (callback) callback(newItem)
54
+ // }
55
+ // }, [itemList])
56
+
57
+ useEffect(() => {
58
+ if (selectedIndex && itemList[selectedIndex]) {
59
+ setSelected(itemList[selectedIndex])
60
+ }
61
+ }, [selectedIndex])
62
+
63
+ useEffect(() => {
64
+ // 表示itemList已经变更
65
+ if (
66
+ !_find(itemList, _item => {
67
+ return _item.id == selected.id && _item.name == selected.name
68
+ })
69
+ ) {
70
+ let newItem: DropItem = (selectedIndex !== undefined ? itemList[selectedIndex] : itemList[0]) || itemList[0]
71
+ setSelected(newItem)
72
+ }
73
+ }, [itemList])
74
+
75
+ return (
76
+ <Listbox value={selected} onChange={handleSelect}>
77
+ {({ open }) => (
78
+ <>
79
+ {title ? (
80
+ <Listbox.Label className="block text-sm font-medium leading-6 text-gray-900">
81
+ {title}
82
+ </Listbox.Label>
83
+ ) : null}
84
+ <div className="relative mt-2">
85
+ <Listbox.Button
86
+ id={domID || ''}
87
+ className="relative w-full cursor-default rounded-md bg-white py-1.5 pl-3 pr-10 text-left text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 sm:text-sm sm:leading-6"
88
+ >
89
+ <span className="flex items-start">
90
+ {selected?.icon ? (
91
+ <img src={selected.icon} alt="" className="h-5 w-5 flex-shrink-0 rounded-full" />
92
+ ) : null}
93
+ <span className=" block truncate h-6">{selected.name}</span>
94
+ </span>
95
+ <span className="pointer-events-none absolute inset-y-0 right-0 ml-3 flex items-center pr-2">
96
+ <ChevronUpDownIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
97
+ </span>
98
+ </Listbox.Button>
99
+
100
+ <Transition
101
+ show={open}
102
+ as={Fragment}
103
+ leave="transition ease-in duration-100"
104
+ leaveFrom="opacity-100"
105
+ leaveTo="opacity-0"
106
+ >
107
+ <Listbox.Options className="absolute z-10 mt-1 max-h-56 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
108
+ {itemList.map(item => (
109
+ <Listbox.Option
110
+ key={item.id}
111
+ className={({ active }) =>
112
+ `${
113
+ active ? 'bg-indigo-600 text-white' : 'text-gray-900'
114
+ } relative cursor-default select-none py-2 pl-3 pr-9`
115
+ }
116
+ value={item}
117
+ >
118
+ {({ selected, active }) => (
119
+ <>
120
+ <div className="flex items-center">
121
+ {item.icon ? (
122
+ <img
123
+ src={item.icon}
124
+ alt=""
125
+ className="h-5 w-5 flex-shrink-0 rounded-full"
126
+ />
127
+ ) : null}
128
+ <span
129
+ className={`${
130
+ selected ? 'font-semibold' : 'font-normal'
131
+ } 'ml-3 block truncate`}
132
+ >
133
+ {item.name}
134
+ </span>
135
+ </div>
136
+
137
+ {selected ? (
138
+ <span
139
+ className={`${
140
+ active ? 'text-white' : 'text-indigo-600'
141
+ } absolute inset-y-0 right-0 flex items-center pr-4`}
142
+ >
143
+ <CheckIcon className="h-5 w-5" aria-hidden="true" />
144
+ </span>
145
+ ) : null}
146
+ </>
147
+ )}
148
+ </Listbox.Option>
149
+ ))}
150
+ </Listbox.Options>
151
+ </Transition>
152
+ </div>
153
+ </>
154
+ )}
155
+ </Listbox>
156
+ )
157
+ }
@@ -0,0 +1,14 @@
1
+ const SVGPlay = ({ className }: { className?: string }) => {
2
+ const svgTest = `
3
+ <svg width="64" height="64" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
4
+ <path fill="#ffffff" d="M2.93 17.07A10 10 0 1 1 17.07 2.93A10 10 0 0 1 2.93 17.07zm12.73-1.41A8 8 0 1 0 4.34 4.34a8 8 0 0 0 11.32 11.32zM7 6l8 4l-8 4V6z"/>
5
+ </svg>
6
+ `
7
+
8
+ const base64String = btoa(svgTest)
9
+
10
+ const imgSrc = `data:image/svg+xml;base64,${base64String}`
11
+ return <img src={imgSrc} className={className || ''} />
12
+ }
13
+
14
+ export default SVGPlay
Binary file
@@ -0,0 +1,27 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ :root {
6
+ --foreground-rgb: 255, 255, 255;
7
+ --background-start-rgb: 255, 255, 255;
8
+ --background-end-rgb: 255, 255, 255;
9
+ }
10
+
11
+ @media (prefers-color-scheme: dark) {
12
+ :root {
13
+ --foreground-rgb: 255, 255, 255;
14
+ --background-start-rgb: 255, 255, 255;
15
+ --background-end-rgb: 255, 255, 255;
16
+ }
17
+ }
18
+
19
+ body {
20
+ color: rgb(var(--foreground-rgb));
21
+ background: linear-gradient(
22
+ to bottom,
23
+ transparent,
24
+ rgb(var(--background-end-rgb))
25
+ )
26
+ rgb(var(--background-start-rgb));
27
+ }
package/app/layout.tsx ADDED
@@ -0,0 +1,15 @@
1
+ import './globals.css'
2
+ import type { Metadata } from 'next'
3
+
4
+ export const metadata: Metadata = {
5
+ title: 'iPhoneOrder',
6
+ description: 'iPhoneOrder',
7
+ }
8
+
9
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
10
+ return (
11
+ <html lang="en">
12
+ <body className={''}>{children}</body>
13
+ </html>
14
+ )
15
+ }
package/app/page.tsx ADDED
@@ -0,0 +1,3 @@
1
+ export default function Home() {
2
+ return <main className="flex min-h-screen flex-col items-center justify-between p-24"></main>
3
+ }