diff --git a/03_source/mobile/src/PATHS.ts b/03_source/mobile/src/PATHS.ts index bca10ac..fc3883a 100644 --- a/03_source/mobile/src/PATHS.ts +++ b/03_source/mobile/src/PATHS.ts @@ -108,6 +108,8 @@ const PATHS = { CAROUSELL_ME_QR: '/tabs/carousell_me/qr_page', CAROUSELL_ME_SETTINGS: '/carousell_me/settings', CAROUSELL_ME_INSIGHTS: '/tabs/carousell_me/insights', + CAROUSELL_ME_OFFERS_MADE: '/tabs/carousell_me/OffersMade', + CAROUSELL_ME_MY_PROFILE: '/tabs/carousell_me/my_profile', // HOTEL_WELCOME_TOUR: '/hotel_service_intro', HOTEL_INTRO: '/tabs/hotel_intro', diff --git a/03_source/mobile/src/api/getCategory.tsx b/03_source/mobile/src/api/getCategory.tsx new file mode 100644 index 0000000..3df08af --- /dev/null +++ b/03_source/mobile/src/api/getCategory.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import getTestSvg from './getTestSvg'; + +async function getCategory(): Promise { + let list = [ + { name: 'Following', avatar: '' }, + { name: 'Computers & Tech', avatar: '' }, + { name: "Women's Fashion", avatar: '' }, + { name: "Men's Fashion", avatar: '' }, + { name: 'Beauty & Personal Care', avatar: '' }, + { name: 'Free Items', avatar: '' }, + { name: 'Audio', avatar: '' }, + { name: 'Furniture & Home Living', avatar: '' }, + { name: 'Babies & Kids', avatar: '' }, + { name: 'Health & Nutrition', avatar: '' }, + { name: 'Food & Drinks', avatar: '' }, + { name: 'Tickets & Vouchers', avatar: '' }, + { name: 'Auto Accessories', avatar: '' }, + { name: 'Community', avatar: '' }, + { name: 'Looking For', avatar: '' }, + { name: 'Announcements', avatar: '' }, + { name: 'Services', avatar: '' }, + { name: 'Mobile Phones & Gadgets', avatar: '' }, + { name: 'Property', avatar: '' }, + { name: 'Cars', avatar: '' }, + { name: 'Luxury', avatar: '' }, + { name: 'Video Gaming', avatar: '' }, + { name: 'Photography', avatar: '' }, + { name: 'TV & Home Appliances', avatar: '' }, + { name: 'Hobbies & Toys', avatar: '' }, + { name: 'Sports', avatar: '' }, + { name: 'Equipment', avatar: '' }, + { name: 'Pet Supplies', avatar: '' }, + { name: 'Motorbikes', avatar: '' }, + { name: 'Jobs', avatar: '' }, + { name: 'Preorders', avatar: '' }, + { name: 'Everything Else', avatar: '' }, + ]; + + for (var i = 0; i < list.length; i++) { + list[i].avatar = await getTestSvg(); + } + + return new Promise((res, rej) => { + res(list); + }); +} + +export default getCategory; diff --git a/03_source/mobile/src/api/getFreshFinds.tsx b/03_source/mobile/src/api/getFreshFinds.tsx new file mode 100644 index 0000000..86e2bdf --- /dev/null +++ b/03_source/mobile/src/api/getFreshFinds.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import getUnsplashRandomImage from './getUnsplashRandomImage'; + +const ContentMd = `幫個忙,睇埋落去先啦.... + +🈺 視乎難度收費,或者你比個 budget plan 諗下都得 +Charge subject to difficulties with the task(s), or bring your budget plan to me... + +💁‍♂️ 服務內容 : +- 代寫程式 ... ( html/javascript/python coding commission) +- 簡易 個人 / 公司網站 / 靜態網站 製作 (static/pwa webpage) +- 網店 / 網購平台製作, 網址 / 域名註冊,網站發佈 (deploy) +- 手機應用程式 (expo/ionic/android) +- 任何自定義 / 量身定做方案, 其他 IT 相關解決方案 (solution / AI) +- Wordpress 公司/個人網頁 +- 網上資料搜集 scraping/harvesting/crawing +- source code 想知點解咁寫開聲問,唔明講到你明 +- 補習 / 指導 + - 如需補習/備課的話,請給我看看所需要課堂資料或者問題, + - 我對你個人資料沒有興趣,你大可以將個人資料屏蔽先 send 比我 + - 世界這麼大,我只是想知道你遇到什麽問題,謝謝 +- 寫bot (請先 PM 我, 要睇睇目的先答做唔做.... book場/搶飛 唔洗問 😊) + +💬 吹水閒偈/諮詢攞下意見免費 😊 (睇心情 / 難度答 😂) +Please DM / PM consultation for free ( But no guaranteed answer... depends... ) + +👋 髒話說在前面 ( Salutations being said in front ) : +- 一般黎講,我會維持對客人應有嘅禮貌同埋尊重 (a.k.a. 互相尊重, implicatively 講左D乜請自己諗... ) +- 同一時間我嘅禮貎都只會展示俾對我有禮貌嘅人睇。 +- 我就是我本人,不是中介,由對接到做嘅都係我,有懷疑者不用找我 👋 👋 。 +- 我唔係你肚入面條蟲,我唔會知你心入面有乜 requirement ... 最簡單係叫你比份 requirements/pdf 我,如果你覺得比個原始 file 我係好難接受嘅話(前題係當然你可以預先 blur 敏感資料),唔使搵我👋 👋 + +多謝你睇到喱度,我知我好長氣,若然仲有興趣搵我做野的話, +第一句同我講 “Hi, 寶達邨的豬~”,我會講整個購物體驗應該會對你有利 😊... +完... + +🍖 Some demo: +- some site demos: +https://louiscklaw.github.io/work + +若果想做 opencv/machine learning 野,可到此 post +https://www.carousell.com.hk/p/1338018892/ + +🔖 Tags: +#reactjs #nodejs #nextjs #typescript #programming #python #html #css #coding #vue #expo #frontend #backend #laravel #github #bot #vba #docker #opencv #mobile-app #LLM #GPT #huggingface #llama #ollama #debug #figma #ICT #opensource #processing #flow-field #網站 #爬蟲 #scraping #RPA #ABAP #FYP #STEM #project #tkinter #shopping-cart #網頁製作 #公司網站 #網店 #整網頁 #一對一教學 #私補 #私教 #補習 #教材 #代編程 #定制程序代寫 #internship #intern #colab #jupyter #raspberry-pi #arduino #openai-gym #gymnasium #app-inventor #microbit #團購 #賭波 #賭馬 #股票 #六合彩 #港股工具 #股票工具 #求助 #28car #智慧轉型 + +#switch2 #switch-2 #adidas #airpods-pro-2 #babymonster #celine #chanel #chiikawa #coach #crybaby #dear jane #dior #fujifilm #fujifilm #goyard #hermes #hermes #ipad #iphone #jellycat #labubu #loewe #longchamp #lululemon #lululemon #lv #macbook #minecraft #pokemon #prada #ps4 #ps5 #rolex #samsung #sony #lego #metal-build #yoga #hottoys #riize #roblox #part-time #街馬-2025 #Blackpink演唱會 #淘佳佳 #i-am-gloria + +# updated: 2025-06-16 +`.trim(); + +const userJson = { + avatar: getUnsplashRandomImage({ keyword: 'hotel' }), + name: 'louis_coding', + since: 'Joined 4 years ago', + verified: true, + rating: 5.0, + total_comment: 37, +}; + +const productSample = { + category: { main: 'Services', sub_cat: ['Learning & Enrichment', 'Enrichment & Tuition'] }, + avatar: getUnsplashRandomImage({ keyword: 'hotel' }), + title: '#html #css #開發 #指導 ', + price: 30, + content: ContentMd, + user: userJson, +}; + +function getFreshFinds(): Promise { + return new Promise((res, rej) => { + res([productSample, productSample, productSample, productSample, productSample, productSample]); + }); +} + +export default getFreshFinds; diff --git a/03_source/mobile/src/api/getProductList.tsx b/03_source/mobile/src/api/getProductList.tsx new file mode 100644 index 0000000..8293cf5 --- /dev/null +++ b/03_source/mobile/src/api/getProductList.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import getUnsplashRandomImage from './getUnsplashRandomImage'; + +const ContentMd = `幫個忙,睇埋落去先啦.... + +🈺 視乎難度收費,或者你比個 budget plan 諗下都得 +Charge subject to difficulties with the task(s), or bring your budget plan to me... + +💁‍♂️ 服務內容 : +- 代寫程式 ... ( html/javascript/python coding commission) +- 簡易 個人 / 公司網站 / 靜態網站 製作 (static/pwa webpage) +- 網店 / 網購平台製作, 網址 / 域名註冊,網站發佈 (deploy) +- 手機應用程式 (expo/ionic/android) +- 任何自定義 / 量身定做方案, 其他 IT 相關解決方案 (solution / AI) +- Wordpress 公司/個人網頁 +- 網上資料搜集 scraping/harvesting/crawing +- source code 想知點解咁寫開聲問,唔明講到你明 +- 補習 / 指導 + - 如需補習/備課的話,請給我看看所需要課堂資料或者問題, + - 我對你個人資料沒有興趣,你大可以將個人資料屏蔽先 send 比我 + - 世界這麼大,我只是想知道你遇到什麽問題,謝謝 +- 寫bot (請先 PM 我, 要睇睇目的先答做唔做.... book場/搶飛 唔洗問 😊) + +💬 吹水閒偈/諮詢攞下意見免費 😊 (睇心情 / 難度答 😂) +Please DM / PM consultation for free ( But no guaranteed answer... depends... ) + +👋 髒話說在前面 ( Salutations being said in front ) : +- 一般黎講,我會維持對客人應有嘅禮貌同埋尊重 (a.k.a. 互相尊重, implicatively 講左D乜請自己諗... ) +- 同一時間我嘅禮貎都只會展示俾對我有禮貌嘅人睇。 +- 我就是我本人,不是中介,由對接到做嘅都係我,有懷疑者不用找我 👋 👋 。 +- 我唔係你肚入面條蟲,我唔會知你心入面有乜 requirement ... 最簡單係叫你比份 requirements/pdf 我,如果你覺得比個原始 file 我係好難接受嘅話(前題係當然你可以預先 blur 敏感資料),唔使搵我👋 👋 + +多謝你睇到喱度,我知我好長氣,若然仲有興趣搵我做野的話, +第一句同我講 “Hi, 寶達邨的豬~”,我會講整個購物體驗應該會對你有利 😊... +完... + +🍖 Some demo: +- some site demos: +https://louiscklaw.github.io/work + +若果想做 opencv/machine learning 野,可到此 post +https://www.carousell.com.hk/p/1338018892/ + +🔖 Tags: +#reactjs #nodejs #nextjs #typescript #programming #python #html #css #coding #vue #expo #frontend #backend #laravel #github #bot #vba #docker #opencv #mobile-app #LLM #GPT #huggingface #llama #ollama #debug #figma #ICT #opensource #processing #flow-field #網站 #爬蟲 #scraping #RPA #ABAP #FYP #STEM #project #tkinter #shopping-cart #網頁製作 #公司網站 #網店 #整網頁 #一對一教學 #私補 #私教 #補習 #教材 #代編程 #定制程序代寫 #internship #intern #colab #jupyter #raspberry-pi #arduino #openai-gym #gymnasium #app-inventor #microbit #團購 #賭波 #賭馬 #股票 #六合彩 #港股工具 #股票工具 #求助 #28car #智慧轉型 + +#switch2 #switch-2 #adidas #airpods-pro-2 #babymonster #celine #chanel #chiikawa #coach #crybaby #dear jane #dior #fujifilm #fujifilm #goyard #hermes #hermes #ipad #iphone #jellycat #labubu #loewe #longchamp #lululemon #lululemon #lv #macbook #minecraft #pokemon #prada #ps4 #ps5 #rolex #samsung #sony #lego #metal-build #yoga #hottoys #riize #roblox #part-time #街馬-2025 #Blackpink演唱會 #淘佳佳 #i-am-gloria + +# updated: 2025-06-16 +`.trim(); + +const userJson = { + avatar: getUnsplashRandomImage({ keyword: 'hotel' }), + name: 'louis_coding', + since: 'Joined 4 years ago', + verified: true, + rating: 5.0, + total_comment: 37, +}; + +const productSample = { + category: { main: 'Services', sub_cat: ['Learning & Enrichment', 'Enrichment & Tuition'] }, + avatar: getUnsplashRandomImage({ keyword: 'hotel' }), + title: '#html #css #開發 #指導 ', + price: 30, + content: ContentMd, + user: userJson, +}; + +function getProductList(): Promise { + return new Promise((res, rej) => { + res([productSample, productSample, productSample, productSample, productSample, productSample]); + }); +} + +export default getProductList; diff --git a/03_source/mobile/src/api/getSegments.tsx b/03_source/mobile/src/api/getSegments.tsx new file mode 100644 index 0000000..c449840 --- /dev/null +++ b/03_source/mobile/src/api/getSegments.tsx @@ -0,0 +1,14 @@ +import React from 'react'; + +function getSegments(): Promise { + return new Promise((res, rej) => { + res([ + { name: 'Top picks', slug: 'top-picks' }, + { name: 'Free items', slug: 'free-items' }, + { name: 'Following', slug: 'following' }, + { name: 'Nearby', slug: 'nearby' }, + ]); + }); +} + +export default getSegments; diff --git a/03_source/mobile/src/api/getSuggestedCategory.tsx b/03_source/mobile/src/api/getSuggestedCategory.tsx new file mode 100644 index 0000000..3b83300 --- /dev/null +++ b/03_source/mobile/src/api/getSuggestedCategory.tsx @@ -0,0 +1,33 @@ +import React from 'react'; + +function getSuggestedCategory(): Promise { + return new Promise((res, rej) => { + res([ + '代做', + 'cisco', + 'm1', + 'pro', + '顯示器支架', + 'kfc', + 'nas', + 'la', + 'prairie', + 'vr', + '代做', + 'cisco', + 'm1', + 'pro', + '顯示器支架', + 'kfc', + 'nas', + 'la', + 'prairie', + 'vr', + '顯示器支架', + 'kfc', + 'nas', + ]); + }); +} + +export default getSuggestedCategory; diff --git a/03_source/mobile/src/api/getTestSvg.tsx b/03_source/mobile/src/api/getTestSvg.tsx new file mode 100644 index 0000000..4ac276f --- /dev/null +++ b/03_source/mobile/src/api/getTestSvg.tsx @@ -0,0 +1,97 @@ +import React from 'react'; + +import airConditioningCoolingHeatTemperatureSvgrepoComSvg from './svgs/air-conditioning-cooling-heat-temperature-svgrepo-com.svg'; +import alertAttentionCautionDangerousWarningSvgrepoComSvg from './svgs/alert-attention-caution-dangerous-warning-svgrepo-com.svg'; +import alertBellCallMessageSignSvgrepoComSvg from './svgs/alert-bell-call-message-sign-svgrepo-com.svg'; +import assistanceBusinessPersonReceptionServiceSvgrepoComSvg from './svgs/assistance-business-person-reception-service-svgrepo-com.svg'; +import bagBaggageLuggageSuitcaseTravelSvgrepoComSvg from './svgs/bag-baggage-luggage-suitcase-travel-svgrepo-com.svg'; +import baggageBellhopHotelServiceWaiterSvgrepoComSvg from './svgs/baggage-bellhop-hotel-service-waiter-svgrepo-com.svg'; +import bagHolidayJourneySuitcaseVacationSvgrepoComSvg from './svgs/bag-holiday-journey-suitcase-vacation-svgrepo-com.svg'; +import bankingFinancialMoneyPaymentTransactionSvgrepoComSvg from './svgs/banking-financial-money-payment-transaction-svgrepo-com.svg'; +import barCafeChairClubStoolSvgrepoComSvg from './svgs/bar-cafe-chair-club-stool-svgrepo-com.svg'; +import bathBathroomCottonTextileTowelSvgrepoComSvg from './svgs/bath-bathroom-cotton-textile-towel-svgrepo-com.svg'; +import bathroomBathtubBubbleFoamWaterSvgrepoComSvg from './svgs/bathroom-bathtub-bubble-foam-water-svgrepo-com.svg'; +import bathroomFaucetRoomSinkWashSvgrepoComSvg from './svgs/bathroom-faucet-room-sink-wash-svgrepo-com.svg'; +import bedFurnitureInteriorPillowRest2SvgrepoComSvg from './svgs/bed-furniture-interior-pillow-rest-2-svgrepo-com.svg'; +import bedFurnitureInteriorPillowRest3SvgrepoComSvg from './svgs/bed-furniture-interior-pillow-rest-3-svgrepo-com.svg'; +import bedFurnitureInteriorPillowRestSvgrepoComSvg from './svgs/bed-furniture-interior-pillow-rest-svgrepo-com.svg'; +import bookCatalogDocumentGuidebookInstructionSvgrepoComSvg from './svgs/book-catalog-document-guidebook-instruction-svgrepo-com.svg'; +import businessFinanceMoneySavingWalletSvgrepoComSvg from './svgs/business-finance-money-saving-wallet-svgrepo-com.svg'; +import cafeCardFoodMenuVintageSvgrepoComSvg from './svgs/cafe-card-food-menu-vintage-svgrepo-com.svg'; +import cafeCupDrinkMugTeaSvgrepoComSvg from './svgs/cafe-cup-drink-mug-tea-svgrepo-com.svg'; +import calendarDateDayMonthTimeSvgrepoComSvg from './svgs/calendar-date-day-month-time-svgrepo-com.svg'; +import cappuccinoCoffeeCupDrinkEspresso2SvgrepoComSvg from './svgs/cappuccino-coffee-cup-drink-espresso-2-svgrepo-com.svg'; +import cappuccinoCoffeeCupDrinkEspressoSvgrepoComSvg from './svgs/cappuccino-coffee-cup-drink-espresso-svgrepo-com.svg'; +import cardCreditCurrencyFinanceMoneySvgrepoComSvg from './svgs/card-credit-currency-finance-money-svgrepo-com.svg'; +import cardDoorKeyLockSecuritySvgrepoComSvg from './svgs/card-door-key-lock-security-svgrepo-com.svg'; +import chairComfortableDecorationGardenTerraceSvgrepoComSvg from './svgs/chair-comfortable-decoration-garden-terrace-svgrepo-com.svg'; +import cleanClothingLaundryWashingWindSvgrepoComSvg from './svgs/clean-clothing-laundry-washing-wind-svgrepo-com.svg'; +import comfortableFabricFootwearShoeSlipperSvgrepoComSvg from './svgs/comfortable-fabric-footwear-shoe-slipper-svgrepo-com.svg'; +import couponEntertainmentEventPaperTicketSvgrepoComSvg from './svgs/coupon-entertainment-event-paper-ticket-svgrepo-com.svg'; +import doorElevatorEntranceFloorLiftSvgrepoComSvg from './svgs/door-elevator-entrance-floor-lift-svgrepo-com.svg'; +import doorEnterEntryExitOpenSvgrepoComSvg from './svgs/door-enter-entry-exit-open-svgrepo-com.svg'; +import doorEntranceHandleKeySecuritySvgrepoComSvg from './svgs/door-entrance-handle-key-security-svgrepo-com.svg'; +import doorKeyLockRoomSecuritySvgrepoComSvg from './svgs/door-key-lock-room-security-svgrepo-com.svg'; +import electronicInternetScreenTechnologyTelevisionSvgrepoComSvg from './svgs/electronic-internet-screen-technology-television-svgrepo-com.svg'; +import holidayHotelJourneyServiceTravel2SvgrepoComSvg from './svgs/holiday-hotel-journey-service-travel-2-svgrepo-com.svg'; +import holidayHotelJourneyServiceTravelSvgrepoComSvg from './svgs/holiday-hotel-journey-service-travel-svgrepo-com.svg'; +import holidayHotelMotelSignTravelSvgrepoComSvg from './svgs/holiday-hotel-motel-sign-travel-svgrepo-com.svg'; +import holidayJourneyLuggageSuitcaseVacation2SvgrepoComSvg from './svgs/holiday-journey-luggage-suitcase-vacation-2-svgrepo-com.svg'; +import hotelLocationMapPinTravelSvgrepoComSvg from './svgs/hotel-location-map-pin-travel-svgrepo-com.svg'; + +const svgList = [ + airConditioningCoolingHeatTemperatureSvgrepoComSvg, + alertAttentionCautionDangerousWarningSvgrepoComSvg, + alertBellCallMessageSignSvgrepoComSvg, + assistanceBusinessPersonReceptionServiceSvgrepoComSvg, + bagBaggageLuggageSuitcaseTravelSvgrepoComSvg, + baggageBellhopHotelServiceWaiterSvgrepoComSvg, + bagHolidayJourneySuitcaseVacationSvgrepoComSvg, + bankingFinancialMoneyPaymentTransactionSvgrepoComSvg, + barCafeChairClubStoolSvgrepoComSvg, + bathBathroomCottonTextileTowelSvgrepoComSvg, + bathroomBathtubBubbleFoamWaterSvgrepoComSvg, + bathroomFaucetRoomSinkWashSvgrepoComSvg, + bedFurnitureInteriorPillowRest2SvgrepoComSvg, + bedFurnitureInteriorPillowRest3SvgrepoComSvg, + bedFurnitureInteriorPillowRestSvgrepoComSvg, + bookCatalogDocumentGuidebookInstructionSvgrepoComSvg, + businessFinanceMoneySavingWalletSvgrepoComSvg, + cafeCardFoodMenuVintageSvgrepoComSvg, + cafeCupDrinkMugTeaSvgrepoComSvg, + calendarDateDayMonthTimeSvgrepoComSvg, + cappuccinoCoffeeCupDrinkEspresso2SvgrepoComSvg, + cappuccinoCoffeeCupDrinkEspressoSvgrepoComSvg, + cardCreditCurrencyFinanceMoneySvgrepoComSvg, + cardDoorKeyLockSecuritySvgrepoComSvg, + chairComfortableDecorationGardenTerraceSvgrepoComSvg, + cleanClothingLaundryWashingWindSvgrepoComSvg, + comfortableFabricFootwearShoeSlipperSvgrepoComSvg, + couponEntertainmentEventPaperTicketSvgrepoComSvg, + doorElevatorEntranceFloorLiftSvgrepoComSvg, + doorEnterEntryExitOpenSvgrepoComSvg, + doorEntranceHandleKeySecuritySvgrepoComSvg, + doorKeyLockRoomSecuritySvgrepoComSvg, + electronicInternetScreenTechnologyTelevisionSvgrepoComSvg, + holidayHotelJourneyServiceTravel2SvgrepoComSvg, + holidayHotelJourneyServiceTravelSvgrepoComSvg, + holidayHotelMotelSignTravelSvgrepoComSvg, + holidayJourneyLuggageSuitcaseVacation2SvgrepoComSvg, + hotelLocationMapPinTravelSvgrepoComSvg, +]; + +function getRandomInt(max: number) { + return Math.floor(Math.random() * max); +} + +function getTestSvg(): Promise { + let { length } = svgList; + let randomIdx = getRandomInt(length - 1); + + console.log({ findme: svgList[randomIdx] }); + return new Promise((res, rej) => { + res(svgList[randomIdx]); + }); +} + +export default getTestSvg; diff --git a/03_source/mobile/src/api/getTopPicks.tsx b/03_source/mobile/src/api/getTopPicks.tsx new file mode 100644 index 0000000..9c08d82 --- /dev/null +++ b/03_source/mobile/src/api/getTopPicks.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import getUnsplashRandomImage from './getUnsplashRandomImage'; + +const ContentMd = `helloworld `.trim(); + +const userJson = { + avatar: getUnsplashRandomImage({ keyword: 'hotel' }), + name: 'louis_coding', + since: 'Joined 4 years ago', + verified: true, + rating: 5.0, + total_comment: 37, +}; + +const productSample = { + category: { main: 'Services', sub_cat: ['Learning & Enrichment', 'Enrichment & Tuition'] }, + avatar: getUnsplashRandomImage({ keyword: 'hotel' }), + title: '#html #css #開發 #指導 ', + price: 30, + content: ContentMd, + user: userJson, +}; + +function getTopPicks(): Promise { + return new Promise((res, rej) => { + res([ + productSample, + productSample, + productSample, + productSample, + productSample, + productSample, + productSample, + ]); + }); +} + +export default getTopPicks; diff --git a/03_source/mobile/src/api/getTopSearches.tsx b/03_source/mobile/src/api/getTopSearches.tsx new file mode 100644 index 0000000..945196f --- /dev/null +++ b/03_source/mobile/src/api/getTopSearches.tsx @@ -0,0 +1,60 @@ +import React from 'react'; + +function getTopSearches(): Promise { + return new Promise((res, rej) => { + res([ + 'blackpink', + 'ps5', + 'blackpink 演唱會', + 'chanel', + 'iphone', + '陳奕迅演唱會', + 'hermes', + '海港城coupon', + '利是封', + 'ipad', + 'apple watch', + 'dior', + 'celine', + '迪士尼門票', + 'lv', + 'nike', + '張敬軒', + 'gucci', + 'lego', + 'ps4', + 'loewe', + 'casetify', + '單車', + 'eason 演唱會', + 'rolex', + 'slam dunk', + 'airpods pro', + 'coach', + '電視', + 'bearbrick', + '雪櫃', + 'mc', + 'prada', + 'samsung', + 'dyson', + 'burberry', + '張敬軒演唱會', + 'pokemon', + 'ikea', + 'linabell', + 'dunk low', + '陳奕迅', + 'balenciaga', + '梳化', + 'mirror', + 'sony', + '麻雀', + 'tory burch', + 'marshall', + '行李箱', + ]); + }); +} + +export default getTopSearches; diff --git a/03_source/mobile/src/api/getYourDailyPicks.tsx b/03_source/mobile/src/api/getYourDailyPicks.tsx new file mode 100644 index 0000000..a213379 --- /dev/null +++ b/03_source/mobile/src/api/getYourDailyPicks.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import getUnsplashRandomImage from './getUnsplashRandomImage'; + +const ContentMd = `幫個忙,睇埋落去先啦.... + +🈺 視乎難度收費,或者你比個 budget plan 諗下都得 +Charge subject to difficulties with the task(s), or bring your budget plan to me... + +💁‍♂️ 服務內容 : +- 代寫程式 ... ( html/javascript/python coding commission) +- 簡易 個人 / 公司網站 / 靜態網站 製作 (static/pwa webpage) +- 網店 / 網購平台製作, 網址 / 域名註冊,網站發佈 (deploy) +- 手機應用程式 (expo/ionic/android) +- 任何自定義 / 量身定做方案, 其他 IT 相關解決方案 (solution / AI) +- Wordpress 公司/個人網頁 +- 網上資料搜集 scraping/harvesting/crawing +- source code 想知點解咁寫開聲問,唔明講到你明 +- 補習 / 指導 + - 如需補習/備課的話,請給我看看所需要課堂資料或者問題, + - 我對你個人資料沒有興趣,你大可以將個人資料屏蔽先 send 比我 + - 世界這麼大,我只是想知道你遇到什麽問題,謝謝 +- 寫bot (請先 PM 我, 要睇睇目的先答做唔做.... book場/搶飛 唔洗問 😊) + +💬 吹水閒偈/諮詢攞下意見免費 😊 (睇心情 / 難度答 😂) +Please DM / PM consultation for free ( But no guaranteed answer... depends... ) + +👋 髒話說在前面 ( Salutations being said in front ) : +- 一般黎講,我會維持對客人應有嘅禮貌同埋尊重 (a.k.a. 互相尊重, implicatively 講左D乜請自己諗... ) +- 同一時間我嘅禮貎都只會展示俾對我有禮貌嘅人睇。 +- 我就是我本人,不是中介,由對接到做嘅都係我,有懷疑者不用找我 👋 👋 。 +- 我唔係你肚入面條蟲,我唔會知你心入面有乜 requirement ... 最簡單係叫你比份 requirements/pdf 我,如果你覺得比個原始 file 我係好難接受嘅話(前題係當然你可以預先 blur 敏感資料),唔使搵我👋 👋 + +多謝你睇到喱度,我知我好長氣,若然仲有興趣搵我做野的話, +第一句同我講 “Hi, 寶達邨的豬~”,我會講整個購物體驗應該會對你有利 😊... +完... + +🍖 Some demo: +- some site demos: +https://louiscklaw.github.io/work + +若果想做 opencv/machine learning 野,可到此 post +https://www.carousell.com.hk/p/1338018892/ + +🔖 Tags: +#reactjs #nodejs #nextjs #typescript #programming #python #html #css #coding #vue #expo #frontend #backend #laravel #github #bot #vba #docker #opencv #mobile-app #LLM #GPT #huggingface #llama #ollama #debug #figma #ICT #opensource #processing #flow-field #網站 #爬蟲 #scraping #RPA #ABAP #FYP #STEM #project #tkinter #shopping-cart #網頁製作 #公司網站 #網店 #整網頁 #一對一教學 #私補 #私教 #補習 #教材 #代編程 #定制程序代寫 #internship #intern #colab #jupyter #raspberry-pi #arduino #openai-gym #gymnasium #app-inventor #microbit #團購 #賭波 #賭馬 #股票 #六合彩 #港股工具 #股票工具 #求助 #28car #智慧轉型 + +#switch2 #switch-2 #adidas #airpods-pro-2 #babymonster #celine #chanel #chiikawa #coach #crybaby #dear jane #dior #fujifilm #fujifilm #goyard #hermes #hermes #ipad #iphone #jellycat #labubu #loewe #longchamp #lululemon #lululemon #lv #macbook #minecraft #pokemon #prada #ps4 #ps5 #rolex #samsung #sony #lego #metal-build #yoga #hottoys #riize #roblox #part-time #街馬-2025 #Blackpink演唱會 #淘佳佳 #i-am-gloria + +# updated: 2025-06-16 +`.trim(); + +const userJson = { + avatar: getUnsplashRandomImage({ keyword: 'hotel' }), + name: 'louis_coding', + since: 'Joined 4 years ago', + verified: true, + rating: 5.0, + total_comment: 37, +}; + +const productSample = { + category: { main: 'Services', sub_cat: ['Learning & Enrichment', 'Enrichment & Tuition'] }, + avatar: getUnsplashRandomImage({ keyword: 'hotel' }), + title: '#html #css #開發 #指導 ', + price: 30, + content: ContentMd, + user: userJson, +}; + +function getYourDailyPicks(): Promise { + return new Promise((res, rej) => { + res([productSample, productSample, productSample, productSample, productSample, productSample]); + }); +} + +export default getYourDailyPicks; diff --git a/03_source/mobile/src/components/ProductCard/index.tsx b/03_source/mobile/src/components/ProductCard/index.tsx new file mode 100644 index 0000000..dc97e7b --- /dev/null +++ b/03_source/mobile/src/components/ProductCard/index.tsx @@ -0,0 +1,71 @@ +import React, { useState } from 'react'; + +import { + IonHeader, + IonTitle, + IonToolbar, + IonContent, + IonPage, + IonButtons, + IonBadge, + IonMenuButton, + IonButton, + IonIcon, + IonDatetime, + IonSelectOption, + IonList, + IonItem, + IonLabel, + IonSelect, + IonPopover, + IonText, + IonCard, + IonCardHeader, + IonCardTitle, + IonCardSubtitle, + IonCardContent, + IonTabs, + IonTabBar, + IonTabButton, + IonSegment, + IonSegmentButton, + useIonRouter, + IonSearchbar, + IonRow, + IonCol, +} from '@ionic/react'; + +// const ProductCard: React.FC = ({product}) => +function ProductCard({ product }: { product: any }) { + return ( + <> + console.log('helloworld')} + > +
+ + + {'#html #css #開發 #指導 #代做 #電子平台 #programming #coding #javascript #python #react #debug' + .split('') + .slice(0, 20)} + + Card Subtitle + + View Insights +
+ + ); +} + +export default ProductCard; diff --git a/03_source/mobile/src/components/TopPicksProductCard/index.tsx b/03_source/mobile/src/components/TopPicksProductCard/index.tsx new file mode 100644 index 0000000..5b96a62 --- /dev/null +++ b/03_source/mobile/src/components/TopPicksProductCard/index.tsx @@ -0,0 +1,46 @@ +import { + IonCard, + IonCardHeader, + IonCardTitle, + IonCardSubtitle, + IonCardContent, +} from '@ionic/react'; + +// const ProductCard: React.FC = ({product}) => +function TopPicksProductCard({ product }: { product: any }) { + return ( + <> + console.log('helloworld')} + > +
+ + + {'#html #css #開發 #指導 #代做 #電子平台 #programming #coding #javascript #python #react #debug' + .split('') + .slice(0, 20)} + + Card Subtitle + + View Insights +
+ + ); +} + +export default TopPicksProductCard; diff --git a/03_source/mobile/src/pages/Carousell/Home/Following.tsx b/03_source/mobile/src/pages/Carousell/Home/Following.tsx new file mode 100644 index 0000000..edd1ba6 --- /dev/null +++ b/03_source/mobile/src/pages/Carousell/Home/Following.tsx @@ -0,0 +1,8 @@ +import React from 'react'; + +function Following({ hide }: { hide: boolean }) { + if (hide) return <>; + return <>Following; +} + +export default Following; diff --git a/03_source/mobile/src/pages/Carousell/Home/FreeItems.tsx b/03_source/mobile/src/pages/Carousell/Home/FreeItems.tsx new file mode 100644 index 0000000..5049cb9 --- /dev/null +++ b/03_source/mobile/src/pages/Carousell/Home/FreeItems.tsx @@ -0,0 +1,8 @@ +import React from 'react'; + +function FreeItems({ hide }: { hide: boolean }) { + if (hide) return <>; + return <>FreeItems; +} + +export default FreeItems; diff --git a/03_source/mobile/src/pages/Carousell/Home/Nearby.tsx b/03_source/mobile/src/pages/Carousell/Home/Nearby.tsx new file mode 100644 index 0000000..b87fdc2 --- /dev/null +++ b/03_source/mobile/src/pages/Carousell/Home/Nearby.tsx @@ -0,0 +1,8 @@ +import React from 'react'; + +function Nearby({ hide }: { hide: boolean }) { + if (hide) return <>; + return <>Nearby; +} + +export default Nearby; diff --git a/03_source/mobile/src/pages/Carousell/Home/TopPicks.tsx b/03_source/mobile/src/pages/Carousell/Home/TopPicks.tsx new file mode 100644 index 0000000..fef444e --- /dev/null +++ b/03_source/mobile/src/pages/Carousell/Home/TopPicks.tsx @@ -0,0 +1,57 @@ +import { useState, useEffect } from 'react'; +import { IonCol, IonRow, IonGrid } from '@ionic/react'; +import getTopPicks from '../../../api/getTopPicks'; +import TopPicksProductCard from '../../../components/TopPicksProductCard'; +import { IonInfiniteScrollCustomEvent } from '@ionic/core'; + +function TopPicks({ hide }: { hide: boolean }) { + const [items, setItems] = useState([]); + const [topPicks, setTopPicks] = useState([]); + + const generateItems = () => { + const newItems = []; + for (let i = 0; i < 50; i++) { + newItems.push(`Item ${1 + items.length + i}`); + } + setItems([...items, ...newItems]); + }; + + const initialLoadTopPicks = () => { + getTopPicks().then((res: any) => setTopPicks(res)); + }; + const loadTopPicksOnScroll = (ev: IonInfiniteScrollCustomEvent) => { + getTopPicks() + .then((res: any) => setTopPicks([...topPicks, ...res])) + .then(() => { + ev.target.complete(); + }); + }; + + useEffect(() => { + generateItems(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + initialLoadTopPicks(); + }, []); + + if (hide) return <>; + return ( + <> +
+ + + {topPicks.map((product: any) => ( + + + + ))} + + +
+ + ); +} + +export default TopPicks; diff --git a/03_source/mobile/src/pages/Carousell/Home/index.tsx b/03_source/mobile/src/pages/Carousell/Home/index.tsx new file mode 100644 index 0000000..3803142 --- /dev/null +++ b/03_source/mobile/src/pages/Carousell/Home/index.tsx @@ -0,0 +1,429 @@ +import { + createGesture, + IonBackButton, + IonButton, + IonButtons, + IonChip, + IonCol, + IonContent, + IonGrid, + IonHeader, + IonIcon, + IonItem, + IonItemDivider, + IonItemGroup, + IonLabel, + IonList, + IonPage, + IonPopover, + IonRefresher, + IonRefresherContent, + IonRow, + IonSegment, + IonSegmentButton, + // IonSlide, + // IonSlides, + IonText, + IonToolbar, + RefresherEventDetail, + IonCard, +} from '@ionic/react'; +import React, { useEffect, useRef, useState } from 'react'; +// import { SuperTabsContainer, SuperTab, SuperTabs, SuperTabsToolbar, SuperTabButton } from '@ionic-super-tabs/react'; +import { + star, + home, + heart, + pin, + call, + globe, + basket, + barbell, + trash, + person, +} from 'ionicons/icons'; + +import { + mailSharp, + chevronDownSharp, + chevronForwardSharp, + arrowBackSharp, + starOutline, + share, + chevronDownCircleOutline, + chevronForwardOutline, + chatbubblesOutline, + menuOutline, +} from 'ionicons/icons'; + +import ProductCard from '../../../components/ProductCard'; +// +import getSuggestedCategory from '../../../api/getSuggestedCategory'; +import getProductList from '../../../api/getProductList'; +import getTopSearches from '../../../api/getTopSearches'; +import getCategory from '../../../api/getCategory'; +import getYourDailyPicks from '../../../api/getYourDailyPicks'; +import getFreshFinds from '../../../api/getFreshFinds'; +import getSegments from '../../../api/getSegments'; +import TopPicks from './TopPicks'; +import Following from './Following'; +import FreeItems from './FreeItems'; +import Nearby from './Nearby'; + +import './style.scss'; + +interface CarousellHome {} + +const Card = () => ( + <> + HelloCard + +); + +const CarousellHome: React.FC = () => { + const [showPopover, setShowPopover] = useState(false); + const [popoverEvent, setPopoverEvent] = useState(); + const [location, setLocation] = useState<'madison' | 'austin' | 'chicago' | 'seattle'>('madison'); + const [conferenceDate, setConferenceDate] = useState('2047-05-17T00:00:00-05:00'); + + const pageRef = useRef(); + + const handleRefresh = (event: CustomEvent) => { + setTimeout(() => { + // Any calls to load data go here + event.detail.complete(); + }, 2000); + }; + + const [suggestedCategories, setSuggestedCategories] = useState([]); + useEffect(() => { + getSuggestedCategory().then((res: any) => setSuggestedCategories(res)); + }, []); + + const [categories, setCategories] = useState([]); + useEffect(() => { + getCategory().then((res: any) => setCategories(res)); + }, []); + + const [productList, setProductList] = useState([]); + useEffect(() => { + getProductList().then((res: any) => setProductList(res)); + }, []); + + const [yourDailyPicks, setYourDailyPicks] = useState([]); + useEffect(() => { + getYourDailyPicks().then((res: any) => setYourDailyPicks(res)); + }, []); + + const [freshFinds, setFreshFinds] = useState([]); + useEffect(() => { + getFreshFinds().then((res: any) => setFreshFinds(res)); + }, []); + + const [topSearches, setTopSearches] = useState([]); + useEffect(() => { + getTopSearches().then((res: any) => setTopSearches(res)); + }, []); + + const [categorySegments, setCategorySegments] = useState([]); + const [segment, setSegment] = useState(''); + useEffect(() => { + getSegments().then((res: any) => { + setCategorySegments(res); + setSegment(res[0].slug); + }); + }, []); + + const onMove = (detail: any) => { + console.log({ detail }); + }; + const segmentRef = useRef(null); + useEffect(() => { + if (segmentRef?.current) { + const gesture = createGesture({ + gestureName: 'helloworld', + el: segmentRef.current, + onMove: (detail) => { + onMove(detail); + }, + }); + gesture.enable(); + } + }, [segmentRef]); + + // const slider = useRef(null); + const [value, setValue] = useState('0'); + const slideOpts = { + initialSlide: 0, + speed: 400, + loop: false, + pagination: { + el: null, + }, + }; + const handleSlideChange = async (event: any) => { + let index: number = 0; + await event.target.getActiveIndex().then((value: any) => { + index = value; + }); + setSegment(categorySegments[index].slug); + setValue('' + index); + }; + + return ( + + + + CarousellLogo + + {}}> + + + {}}> + + + + + + + +
+
+
一個網上申請 多個貸款報價任您揀!
+
+ +
+
+ top button placeholder +
+
+ +
+
+ slider placeholder +
+
+
+ +
+ + + +
Looks like your kinda thing
+
+ +
+
+ {suggestedCategories.map((category: any, index: number) => ( +
+ {category} +
+ ))} +
+
+
+ + + +
Explore Carousell
+
+ +
+ +
+
+ {categories.map((category: any, index: number) => ( +
+
+
+
+
+ {category.name || ''} +
+
+ ))} +
+
+ +
+
+
+
+ + + +
Your Daily Picks
+
+ +
+
+ {yourDailyPicks.map((product: any, index: number) => ( + + ))} +
+
+
+ + + +
Fresh Finds
+
+ +
+
+ {freshFinds.map((product: any, index: number) => ( + + ))} +
+
+
+ + + +
Top searches
+
+ +
+
+ {freshFinds.map((product: any, index: number) => ( + + ))} +
+
+
+ + + + { + console.log(e.target); + setSegment(e.detail.value as any); + }} + selectOnFocus + > + {categorySegments.map((seg: any, index: number) => ( + + {seg.name} + + ))} + + + + ion slide should be here + +
+
+ +
+ +
Follow Us
+
+
2023 louiscklaw
+ +
Help Centre
+
Contact Us
+
Press
+
Jobs
+
Advertise with Us
+
Terms
+
Privacy
+
+ +
+
English
+
+ +
+ Explore Carousell Following Computers & Tech Women's Fashion Men's Fashion Beauty & + Personal Care Free Items Audio Furniture & Home Living Babies & Kids Health & Nutrition + Food & Drinks Tickets & Vouchers Auto Accessories Community Looking For Announcements + Services Mobile Phones & Gadgets Property Cars Luxury Video Gaming Photography TV & Home + Appliances Hobbies & Toys Sports Equipment Pet Supplies Motorbikes Jobs Preorders + Everything Else +
+ + + + +
CarousellHome
+
+
+ ); +}; + +export default React.memo(CarousellHome); diff --git a/03_source/mobile/src/pages/Carousell/Home/style.scss b/03_source/mobile/src/pages/Carousell/Home/style.scss new file mode 100644 index 0000000..2f838f4 --- /dev/null +++ b/03_source/mobile/src/pages/Carousell/Home/style.scss @@ -0,0 +1,32 @@ +#carousell-home-page { + ::-webkit-scrollbar, + *::-webkit-scrollbar { + display: none; + } + + ion-slides { + --offset-bottom: auto !important; + --overflow: hidden; + overflow: auto; + &::-webkit-scrollbar { + display: none; + } + } + + #top-pick-product-list { + ion-card { + --margin-inline: 0; + } + } + + #top-picks { + --padding-start: 0; + --inner-padding-start: 0; + --padding-end: 0; + --inner-padding-end: 0; + + ion-item { + --background: gold; + } + } +} diff --git a/03_source/mobile/src/pages/Carousell/ProductPage/index.tsx b/03_source/mobile/src/pages/Carousell/ProductPage/index.tsx new file mode 100644 index 0000000..b119911 --- /dev/null +++ b/03_source/mobile/src/pages/Carousell/ProductPage/index.tsx @@ -0,0 +1,410 @@ +import { + IonBackButton, + IonBreadcrumb, + IonBreadcrumbs, + IonButton, + IonButtons, + IonChip, + IonContent, + IonIcon, + IonPage, + IonText, + IonToolbar, + ScrollDetail, + useIonRouter, + useIonViewDidEnter, + useIonViewWillEnter, + useIonViewWillLeave, + IonCard, +} from '@ionic/react'; + +import { + heartOutline, + shareOutline, + flagOutline, + timerOutline, + pricetagOutline, +} from 'ionicons/icons'; + +import React, { useContext, useEffect, useRef, useState } from 'react'; + +// import AboutPopover from '../../components/AboutPopover'; +import { useIonAlert } from '@ionic/react'; +import StarRatings from 'react-star-ratings'; + +import './style.scss'; +import { AppContext } from '../../../data/AppContext'; +import { createGesture } from '@ionic/react'; +import ReactMarkdown from 'react-markdown'; +import getUnsplashRandomImage from '../../../api/getUnsplashRandomImage'; + +const ContentMd = `helloworld`.trim(); + +const userJson = { + avatar: getUnsplashRandomImage({ keyword: 'hotel' }), + name: 'louis_coding', + since: 'Joined 4 years ago', + verified: true, + rating: 5.0, + total_comment: 37, +}; + +const productSample = { + category: { main: 'Services', sub_cat: ['Learning & Enrichment', 'Enrichment & Tuition'] }, + avatar: getUnsplashRandomImage({ keyword: 'hotel' }), + title: '#html #css #開發 #指導 ', + price: 30, + content: ContentMd, + user: userJson, +}; + +const commentSample = { + user: userJson, + content: '準時有禮', + product: productSample, + time: '5 days', + properties: 'Review from seller', +}; + +const commentList = [commentSample, commentSample, commentSample, commentSample, commentSample]; +const productList = [ + productSample, + productSample, + productSample, + productSample, + productSample, + productSample, +]; + +interface ProductPageProps {} + +const ProductPage: React.FC = () => { + const [showPopover, setShowPopover] = useState(false); + const [popoverEvent, setPopoverEvent] = useState(); + const [location, setLocation] = useState<'madison' | 'austin' | 'chicago' | 'seattle'>('madison'); + const [conferenceDate, setConferenceDate] = useState('2047-05-17T00:00:00-05:00'); + const [showAlert, hideAlert] = useIonAlert(); + + const { browser_store } = useContext(AppContext); + + const refRectangle = useRef(null); + const [swipeType, setSwipeType] = useState(); + const [deltaX, setDeltaX] = useState(); + const [velocityX, setVelocityX] = useState(); + const [swipeVerdict, setSwipeVerdict] = useState('helloworld'); + + const contentRef = useRef(null); + + const route = useIonRouter(); + const [maxBreadcrumbs, setMaxBreadcrumbs] = useState(2); + + const [isPageTop, setIsPageTop] = useState(true); + + useEffect(() => { + if (swipeVerdict == 'swipe-left') + if (route.canGoBack() == true) { + route.goBack(); + } else { + route.push('/tabs/schedule'); + } + }, [swipeVerdict]); + + useIonViewWillEnter(() => {}); + + useIonViewWillLeave(() => {}); + + const onMove = (detail: any) => { + const type = detail.type; + const currentX = detail.currentX; + const deltaX = detail.deltaX; + const velocityX = detail.velocityX; + setSwipeType(type); + setDeltaX(deltaX); + setVelocityX(velocityX); + + if (type == 'pan') + if (Math.abs(deltaX) > 50) + if (velocityX > 0) { + setSwipeVerdict('swipe-right'); + } else { + setSwipeVerdict('swipe-left'); + } + }; + + useIonViewDidEnter(() => { + let gesture: any = {}; + if (refRectangle?.current) { + gesture = createGesture({ + gestureName: 'helloworld', + el: refRectangle.current, + onMove: (detail) => { + onMove(detail); + }, + }); + + gesture.enable(); + } + + return () => { + gesture?.destroy(); + }; + }, [refRectangle]); + + return ( + + ) => { + if (ev.detail.deltaY > 10) { + setIsPageTop(false); + } else { + setIsPageTop(true); + } + }} + > +
+ + + + + + + {}}> + + + {}}> + + + + +
+ + + +
+ setMaxBreadcrumbs(undefined)} + > + + {productSample.category.main} + + + {productSample.category.sub_cat[0]} + + + {productSample.category.sub_cat[1]} + + + +

{productSample.title}

+
+
+ + + 10 hours ago by kylema11201 + + + + + HK$0 + + + + 234 Likes + + + In Enrichment & Tuition + Type of Rate Hourly +
+

+ {productSample.content} +

+ + read more + + +

Kowloon Tong (九龍塘)

+
+ +

Region Kowloon

+
+ +

Tutor Qualification Master's

+
+ +

Type of Tutor Full-Time Tutor

+
+ +

Levels to Tutor University, Asso, IVE, Secondary

+
+ +

Subjects Stem, Computer Science, IT

+
+ +

Preferred Days / Times TBA

+
+ Share This Listing + Advertisement +
+
+

Meet The Seller

+
+
+ +
+
+

+ {productSample.user.name} +
+ {productSample.user.since} +
+ {productSample.user.verified ? 'Verified' : 'not Verified'} +
+ {}} + numberOfStars={5} + name="rating" + starDimension="1rem" + starSpacing="0px" + // + /> + {productSample.user.rating} ({productSample.user.total_comment})
+

+
+
+
+ {commentList.map((commentJson) => ( +
+
+ +
+ +
+
{commentJson.user.name}
+
{commentJson.content}
+ +
+
+
+
+ {commentJson.product.title} +
+
HK${commentJson.product.price}
+
+
+
+ {commentJson.time}∙{commentJson.properties} +
+
+
+ ))} + + Read all + +
+

What others also search for

+
+ mirror 緣份小卡 + mirror 咭 + maskon mirror + mirror pin + 緣份小卡 + csl mirror card + mirror yes card + mirror csl 交換 + error yes card + mirror tee +
+
+ {/* similar-listings */} +
+

Similar listings

+
+ {productList.map((product) => ( + +
+
+
{product.title}
+
HK${product.price}
+
+
+ ))} +
+
+
+
+
+ ); +}; + +export default React.memo(ProductPage); diff --git a/03_source/mobile/src/pages/Carousell/ProductPage/style.scss b/03_source/mobile/src/pages/Carousell/ProductPage/style.scss new file mode 100644 index 0000000..91620a4 --- /dev/null +++ b/03_source/mobile/src/pages/Carousell/ProductPage/style.scss @@ -0,0 +1,47 @@ +.product-properties { + display: flex; + flex-direction: row; + align-items: center; + + ion-icon { + margin-right: 1rem; + } +} + +#product-page { + .txt-grey { + color: grey; + } + + .product-listing { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + gap: 4%; + row-gap: calc(100vw * 0.04); + } + + ion-card { + width: 48%; + margin: 0; + padding: 0; + + .product-image { + background-size: cover; + background-position: center; + background-repeat: no-repeat; + width: 100%; + height: 100px; + } + + .product-name { + font-weight: bold; + font-size: 0.9rem; + } + + .product-price { + font-size: 0.8rem; + } + } +} diff --git a/03_source/mobile/src/pages/CarousellMe/MyProfile/screencapture-localhost-8081-tabs-carousell-me-my-profile-2025-06-20-02_10_29.png b/03_source/mobile/src/pages/CarousellMe/MyProfile/screencapture-localhost-8081-tabs-carousell-me-my-profile-2025-06-20-02_10_29.png new file mode 100644 index 0000000..35bd5fa Binary files /dev/null and b/03_source/mobile/src/pages/CarousellMe/MyProfile/screencapture-localhost-8081-tabs-carousell-me-my-profile-2025-06-20-02_10_29.png differ diff --git a/03_source/mobile/src/pages/Insights/screencapture-localhost-8081-tabs-carousell-me-insights-2025-06-20-02_11_40.png b/03_source/mobile/src/pages/Insights/screencapture-localhost-8081-tabs-carousell-me-insights-2025-06-20-02_11_40.png new file mode 100644 index 0000000..c293b0f Binary files /dev/null and b/03_source/mobile/src/pages/Insights/screencapture-localhost-8081-tabs-carousell-me-insights-2025-06-20-02_11_40.png differ diff --git a/03_source/mobile/src/pages/MainTabs/index.tsx b/03_source/mobile/src/pages/MainTabs/index.tsx index c11ee70..d654bf9 100644 --- a/03_source/mobile/src/pages/MainTabs/index.tsx +++ b/03_source/mobile/src/pages/MainTabs/index.tsx @@ -20,6 +20,7 @@ import Favourites from '../Favourites'; import Helloworld from '../Helloworld'; import TabAppRoute from '../../TabAppRoute'; import CarousellMe from '../CarousellMe'; +import CarousellMeMyProfile from '../CarousellMe/MyProfile'; import ServiceMenu from './ServiceMenu'; // @@ -70,6 +71,8 @@ import HotelIntro from '../HotelIntro'; import HotelServiceWifi from '../HotelServiceIntro'; import OrderHistory from '../OrderHistory'; import Insights from '../Insights'; +import OffersMade from '../OffersMade'; +import CarousellHome from '../Carousell/Home'; // const hotelServiceMenu = [ @@ -142,11 +145,14 @@ const MainTabs: React.FC = () => { } exact={true} /> + + {/* - - - - */} + */} + + } exact={true} /> + {/* } exact={true} /> */} + {/* } exact={true} /> */} diff --git a/03_source/mobile/src/pages/OffersMade/index.tsx b/03_source/mobile/src/pages/OffersMade/index.tsx new file mode 100644 index 0000000..ad18d24 --- /dev/null +++ b/03_source/mobile/src/pages/OffersMade/index.tsx @@ -0,0 +1,68 @@ +import { + IonBackButton, + IonButton, + IonButtons, + IonContent, + IonHeader, + IonIcon, + IonItem, + IonLabel, + IonList, + IonPage, + IonTitle, + IonToolbar, +} from '@ionic/react'; +import React, { useRef, useState } from 'react'; +// import AboutPopover from '../../../components/AboutPopover'; + +import { star, starOutline, share } from 'ionicons/icons'; +import './style.scss'; +import { useTranslation } from 'react-i18next'; + +interface SampleBlankBottomNav {} + +const OffersMade: React.FC = ({}) => { + const { t } = useTranslation(); + + return ( + <> + + + + + + + +

{t('Offers Made')}

+
+ + + {}}> + {false ? ( + + ) : ( + + )} + + {}}> + + + +
+
+ + + + + +

{t('No items found')}

+
+
+
+
+
+ + ); +}; + +export default React.memo(OffersMade); diff --git a/03_source/mobile/src/pages/OffersMade/screencapture-localhost-8081-tabs-carousell-me-OffersMade-2025-06-20-02_11_15.png b/03_source/mobile/src/pages/OffersMade/screencapture-localhost-8081-tabs-carousell-me-OffersMade-2025-06-20-02_11_15.png new file mode 100644 index 0000000..10ac281 Binary files /dev/null and b/03_source/mobile/src/pages/OffersMade/screencapture-localhost-8081-tabs-carousell-me-OffersMade-2025-06-20-02_11_15.png differ diff --git a/03_source/mobile/src/pages/OffersMade/style.scss b/03_source/mobile/src/pages/OffersMade/style.scss new file mode 100644 index 0000000..417e908 --- /dev/null +++ b/03_source/mobile/src/pages/OffersMade/style.scss @@ -0,0 +1,2 @@ +#sample-blank-bottom-nav-page { +} diff --git a/03_source/mobile/src/pages/tabs/carousell_me/settings/screencapture-localhost-8081-carousell-me-settings-2025-06-20-02_12_04.png b/03_source/mobile/src/pages/tabs/carousell_me/settings/screencapture-localhost-8081-carousell-me-settings-2025-06-20-02_12_04.png new file mode 100644 index 0000000..2af06d0 Binary files /dev/null and b/03_source/mobile/src/pages/tabs/carousell_me/settings/screencapture-localhost-8081-carousell-me-settings-2025-06-20-02_12_04.png differ