iphone-xudale 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }