Cart

The new ContiTube  bicycle tube program makes it easier for you to find the ideal tube for your cycling demands. They offer a selection of tube sizes, types, lengths and dimensions for MTB, Tour, Cross and Race tyres. Varying tube types can affect your tyres’ handling characteristics with little effort: the Standard tube, available in many dimensions, offers the best compromise for everyday cycling. Waterproof design as well as impact and vibration resistantColour div class="featured-image__bg bg-pos-center-center" style="background-image: url('//projektride.co.uk/cdn/shop/files/2571D9FF-E9AE-4004-9A55-C7FD4DD999D6_2048x.jpg?v=1640941114');"> {"id":7485528703202,"title":"Continental MTB 26\" (26 x 1.75\" - 26 x 2.50\") Schrader - 40mm","handle":"continental-mtb-26-26-x-1-75-26-x-2-50-schrader-40mm","description":"\u003cmeta charset=\"utf-8\"\u003e\n\u003cp data-mce-fragment=\"1\"\u003eContinental Inner Tube\u003c\/p\u003e\n\u003cp data-mce-fragment=\"1\"\u003eSize -26'' - 1.75'' - 2.50''\u003c\/p\u003e\n\u003cp data-mce-fragment=\"1\"\u003eValve type - Schrader 40mm\u003c\/p\u003e\n\u003cp data-mce-fragment=\"1\"\u003e\u003cspan data-mce-fragment=\"1\"\u003eI\u003c\/span\u003e\u003cspan data-mce-fragment=\"1\"\u003emages are for illustration purposes only.\u003c\/span\u003e\u003c\/p\u003e\n\u003cp data-mce-fragment=\"1\"\u003e\u003cstrong data-mce-fragment=\"1\"\u003eThe new ContiTube\u003c\/strong\u003e\u003cspan data-mce-fragment=\"1\"\u003e bicycle tube program makes it easier for you to find the ideal tube for your cycling demands. They offer a selection of tube sizes, types, lengths and dimensions for MTB, Tour, Cross and Race tyres. Varying tube types can affect your tyres’ handling characteristics with little effort: the Standard tube, available in many dimensions, offers the best compromise for everyday cycling.\u003c\/span\u003e\u003c\/p\u003e","published_at":"2025-01-07T16:36:38+00:00","created_at":"2021-12-27T12:57:24+00:00","vendor":"Continental","type":"","tags":["spo-cs-disabled","spo-default","spo-disabled","spo-notify-me-disabled","tubes"],"price":799,"price_min":799,"price_max":799,"available":true,"price_varies":false,"compare_at_price":null,"compare_at_price_min":0,"compare_at_price_max":0,"compare_at_price_varies":false,"variants":[{"id":42207132156130,"title":"Default Title","option1":"Default Title","option2":null,"option3":null,"sku":"","requires_shipping":true,"taxable":true,"featured_image":null,"available":true,"name":"Continental MTB 26\" (26 x 1.75\" - 26 x 2.50\") Schrader - 40mm","public_title":null,"options":["Default Title"],"price":799,"weight":0,"compare_at_price":null,"inventory_management":"shopify","barcode":"","requires_selling_plan":false,"selling_plan_allocations":[]}],"images":["\/\/projektride.co.uk\/cdn\/shop\/products\/Screenshot2021-12-26at18.29.09_9be23ed7-fba6-4196-a9dc-cb83e4e1460e.png?v=1640609846"],"featured_image":"\/\/projektride.co.uk\/cdn\/shop\/products\/Screenshot2021-12-26at18.29.09_9be23ed7-fba6-4196-a9dc-cb83e4e1460e.png?v=1640609846","options":["Title"],"media":[{"alt":null,"id":28918158360802,"position":1,"preview_image":{"aspect_ratio":0.744,"height":850,"width":632,"src":"\/\/projektride.co.uk\/cdn\/shop\/products\/Screenshot2021-12-26at18.29.09_9be23ed7-fba6-4196-a9dc-cb83e4e1460e.png?v=1640609846"},"aspect_ratio":0.744,"height":850,"media_type":"image","src":"\/\/projektride.co.uk\/cdn\/shop\/products\/Screenshot2021-12-26at18.29.09_9be23ed7-fba6-4196-a9dc-cb83e4e1460e.png?v=1640609846","width":632}],"requires_selling_plan":false,"selling_plan_groups":[],"content":"\u003cmeta charset=\"utf-8\"\u003e\n\u003cp data-mce-fragment=\"1\"\u003eContinental Inner Tube\u003c\/p\u003e\n\u003cp data-mce-fragment=\"1\"\u003eSize -26'' - 1.75'' - 2.50''\u003c\/p\u003e\n\u003cp data-mce-fragment=\"1\"\u003eValve type - Schrader 40mm\u003c\/p\u003e\n\u003cp data-mce-fragment=\"1\"\u003e\u003cspan data-mce-fragment=\"1\"\u003eI\u003c\/span\u003e\u003cspan data-mce-fragment=\"1\"\u003emages are for illustration purposes only.\u003c\/span\u003e\u003c\/p\u003e\n\u003cp data-mce-fragment=\"1\"\u003e\u003cstrong data-mce-fragment=\"1\"\u003eThe new ContiTube\u003c\/strong\u003e\u003cspan data-mce-fragment=\"1\"\u003e bicycle tube program makes it easier for you to find the ideal tube for your cycling demands. They offer a selection of tube sizes, types, lengths and dimensions for MTB, Tour, Cross and Race tyres. Varying tube types can affect your tyres’ handling characteristics with little effort: the Standard tube, available in many dimensions, offers the best compromise for everyday cycling.\u003c\/span\u003e\u003c\/p\u003e"} Approximately five hours charge time <

< Choose any optional free equipment - shown in the hire section - and add it to your basket so it's ready for you when you pick up your bike. This can also be done in store.img src="//projektride.co.uk/cdn/shop/files/pay_512x512.png?v=1690612532" alt="" class="icons-row__image"> <

Checkout the hire items in your basket and pay with all major credit cards, PayPal or Klarna. Payments can be made in store without going through the online shop. Please call the shop to book out in-person.img src="//projektride.co.uk/cdn/shop/files/confirmation_512x512.png?v=1690612532" alt="" class="icons-row__image"> <

Wait for one of the team to confirm your booking. This is separate from the payment confirmation. A confirmation email will be sent within 24 hours, during shop opening times.img src="//projektride.co.uk/cdn/shop/files/collection_512x512.png?v=1690612759" alt="" class="icons-row__image"> <

5. Collect In Store

Collect your bike in store alongside all optional equipment. Please bring a form of identification (Driver's licence or Passport) to complete the booking. img src="//projektride.co.uk/cdn/shop/files/ride_confident_512x512.png?v=1690612532" alt="" class="icons-row__image">

img src="//projektride.co.uk/cdn/shop/files/ride_confident_512x512.png?v=1690612532" alt="" class="icons-row__image"> 6. Ride Confident!Email

6. Ride Confident!

Enjoy your bike for the hire period! The bike must be returned to the store during opening hours of the return date. #FeaturedImage--template--16831240536290__1d6422c8-bf97-41bc-a8a2-12b01ca58992 { --overlay-opacity: 0.2; }

#FeaturedImage--template--16831240536290__1d6422c8-bf97-41bc-a8a2-12b01ca58992 { --overlay-opacity: 0.2; }
What do you need from me to hire a bike?
What do you need from me to hire a bike?
  • We will require your full name, address and any suitable form of identification such as a passport or a driver's license. window._RestockRocketConfig = window._RestockRocketConfig || {} // Helper function to normalize locale format from hyphen to underscore (e.g., 'en-US' -> 'en_us') // This matches the backend's Mobility.normalize_locale behavior // Returns empty string if locale is empty or invalid (matches original behavior) function normalizeLocale(locale) { if (!locale || locale.trim() === '') { return ''; } return locale.toString().toLowerCase().replace(/-/g, '_'); } window._RestockRocketConfig.locale = 'en'; window._RestockRocketConfig.normalizedLocale = normalizeLocale('en'); window._RestockRocketConfig.shop = 'projektride.myshopify.com'; window._RestockRocketConfig.pageType = 'product'; window._RestockRocketConfig.liquidRenderedAt = 1773111472;window._RestockRocketConfig.marketId = 382140642;window._RestockRocketConfig.countryName = 'United Kingdom'; window._RestockRocketConfig.countryIsoCode = 'GB';window._RestockRocketConfig.cartInventoryQuantity = {};window._RestockRocketConfig.cachedSettings = {"id":38500,"shop_id":38436,"currency":"GBP","created_at":"2025-07-26T09:13:57.337Z","updated_at":"2025-12-28T14:44:23.508Z","enable_app":true,"enable_signup_widget":false,"storefront_button_text":"Notify me when available","storefront_button_text_color":"#FFFFFF","storefront_button_background_color":"#202223","storefront_form_header":"Notify me","storefront_form_description":"Get a notification as soon as this product is back in stock by signing up below!","storefront_form_button_text":"Notify me when available","storefront_form_button_text_color":"#FFFFFF","storefront_form_button_background_color":"#202223","storefront_form_terms":"Promise we won't spam. You'll only receive notifications for this product.","storefront_form_error":"Please enter a valid email address","storefront_form_success":"Thank you! We will notify you when the product is available.","enable_powered_by":true,"show_button_on_preorder":true,"sms_enabled":false,"email_enabled":true,"storefront_button_disable_tag":"rocket-hide","theme_config":{"disableDebugLoggingForNonPreorderItem":false},"storefront_form_email_placeholder":"Email address","storefront_form_phone_placeholder":"SMS","storefront_form_phone_label":"Phone number","storefront_form_email_label":"Email","storefront_form_phone_error":"Please enter a valid phone number","storefront_form_customer_name_placeholder":"Name","storefront_form_customer_name_error":"Please enter your name","storefront_form_did_you_mean_error":"Did you mean %{suggested_email}? Or use %{current_email}","form_customer_name_enabled":false,"form_customer_name_required":false,"css_config":"","js_config":null,"collect_promotion_consent":false,"storefront_form_promotion_consent_label":"Notify me about other news, sales, discounts & offers too","show_button_on_collection":false,"sms_default_country":"us","sms_allowed_countries":[],"sms_restrict_country":false,"sms_default_channel":true,"optin_required":false,"optin_success_text":"Registration confirmed! You'll receive an alert when the product is restocked.","storefront_button_border_radius":0,"storefront_button_disable_tag_hides_button":true,"storefront_button_disable_tag_enabled":false,"quantity_required":false,"storefront_form_quantity_label":"Quantity","enable_alerts":true,"sms_allowed":false,"email_allowed":true,"collect_promotion_consent_default":true,"insert_button_after_selector":null,"insert_button_after_selector_type":"afterend","storefront_button_position_type":"float-right","storefront_form_duplicate_error":"You've already subscribed for alerts to this product.","storefront_mixed_cart_error":"This item needs to be purchased separately. Please check out or clear your cart before adding this item.","storefront_error_heading":"Error","default_locale":"en","collection_page_button_text_color":"#FFFFFF","collection_page_button_background_color":"#202223","show_button_if_any_out_of_stock":false,"show_button_if_any_variant_out_of_stock_collection":false,"show_button_on_index":false,"insert_button_after_selector_collection":null,"insert_button_after_selector_index":null,"push_enabled":false,"push_allowed":false,"storefront_form_push_label":"Push","storefront_form_push_description":"Click 'Allow' to be notified via push notification","storefront_form_push_error":"Permission rejected! Please review notification settings and try again","storefront_font_family":"OpenSans","insert_button_after_selector_collection_type":"afterend","show_channel_selector":false,"storefront_form_empty_error":"Please fill in one or more of the options above","storefront_form_push_input":"Send notification to your browser","insert_button_after_selector_page":null,"show_button_on_page":false,"insert_button_after_selector_search":null,"show_button_on_search":false,"app_proxy_path_prefix":"/apps/restockrocket-production","collection_link_selector":"","index_link_selector":"","page_link_selector":"","search_link_selector":"","collection_check_link_visibility":true,"collection_buttons_container":null,"index_buttons_container":null,"page_buttons_container":null,"search_buttons_container":null,"extension_enable_url_variant_detection":true,"extension_enable_value_variant_detection":true,"extension_value_variant_selector":"[name='id']","resubscribe_text":"This product is out of stock. Get notified when it's restocked again by entering your details below!","preorder_enabled":true,"preorder_buy_button_selector":null,"preorder_add_to_cart_button_selector":"","preorder_badge_selector":"","preorder_button_out_of_stock_text":"Out of stock","preorder_button_add_to_cart_text":"Add to cart","preorder_form_selector":"form[action*=\"/cart/add\"]","preorder_collection_enabled":false,"preorder_collection_form_selector":"form[action*=\"/cart/add\"]","preorder_collection_add_to_cart_button_selector":"form[action*=\"/cart/add\"] button","preorder_index_enabled":false,"preorder_index_form_selector":"form[action*=\"/cart/add\"]","preorder_index_add_to_cart_button_selector":"form[action*=\"/cart/add\"] button","preorder_page_enabled":false,"preorder_page_form_selector":"form[action*=\"/cart/add\"]","preorder_page_add_to_cart_button_selector":"form[action*=\"/cart/add\"] button","preorder_search_enabled":false,"preorder_search_form_selector":"form[action*=\"/cart/add\"]","preorder_search_add_to_cart_button_selector":"form[action*=\"/cart/add\"] button","preorder_collection_badge_selector":null,"preorder_index_badge_selector":null,"preorder_page_badge_selector":null,"preorder_search_badge_selector":null,"preorder_badge_selector_type":"afterend","preorder_collection_badge_selector_type":"afterend","preorder_button_child_selector":"span","preorder_button_disclaimer_insert_selector":"","preorder_button_disclaimer_insert_selector_type":"afterend","preorder_payment_insert_selector":"","preorder_payment_insert_selector_type":"afterend","preorder_price_container_selector":"","preorder_price_container_selector_insert_type":"afterend","preorder_terms_insert_selector":"","preorder_terms_insert_selector_type":"afterend","preorder_original_price_selector":"","preorder_price_format":"{{amount}} {{currency}}","show_badge_if_any_variant_is_preorder":false,"enable_console_debug":false,"inline_form_enabled":false,"inline_form_selector":null,"inline_form_selector_type":"afterend","storefront_form_prefill_customer":true,"storefront_form_show_image":false,"storefront_form_text_color":"#202223","storefront_form_background_color":"#FFFFFF","storefront_form_border_radius":0,"market_setup_type":"single_market","shopify_app_id":5940125,"preorder_progress_bar_insert_selector":null,"preorder_progress_bar_insert_selector_type":"beforebegin","countdown_timer_insert_selector":null,"countdown_timer_insert_selector_type":"afterend","cache":true,"cached_at":"2026-01-08T16:12:13.364Z","multi_language_enabled":false,"translation_locale":"en"};window._RestockRocketConfig.cachedPreorderVariantIds = {"preorder_variant_ids":[42167799447778,43916521013474,4393469258,43936401522914,43936408568034,43936414400738,43936700727522,43936706101474,43936706134242,43936706167010,43936706199778,43936706232546,43936706265314,43938308587746,43938308653282,43938308718818,43938308751586,43938308784354,43938308817122,43938322612450,43938322645218,43938322677986,43981336051938,43981336084706,43981336117474,43981336150242,43981345587426,43981345620194,43981345652962,43981345685730,43981357580514,43981357613282,43981362462946,43981362495714,43981362528482,43981369016546,43981369049314,43981374914786,43981374947554,43981374980322,43981392773346,43981392904418,43981695844578,43981695877346,43981695910114,43981695942882,43981986070754,43981987905762,43981987938530,44052906967266,44052907327714,44052907360482,44052907393250,44052907426018,44052907458786,44052907491554,44052909097186,44052909129954,44140302827746,44140302893282,44140317016290,44155590508770,44155590541538,44155594211554,44155594244322,44155594277090,44155594309858,44155594342626,44155594375394,44155594440930,44155594473698, This will be collected in store when you come to collect the bike.44155594506466,44195991847138,44195991945442,44329993437410,44329993470178,44329993502946,44329993535714,44329993568482,44957136584930,44957136781538,44957136945378,45068753961186,45068753993954,45069622640866,45069622903010,45069622968546,45069750730978,45069750763746,45353010921698,45353010954466,45353010987234,45353018261730,45353018294498,45353018327266,55569712382335,55569712447871,55569712480639,55570550194559,55570550227327,55604008976767,55638316908927,55638316941695,55638316974463,56220814999935,56220815032703,56270279606655,56270279639423,56270279672191,56314171064703,56314171097471,56398983725439,56398983758207,56398983790975,56399322251647,56565020721535,56565020754303,56565020787071],"updated_at":"2026-03-10T02:42:30Z","market_locations_enabled":false,"market_id":382140642,"preorder_location_filter_enabled":false,"preorder_location_filter_ids":[],"collection_id":null};window._RestockRocketConfig.cachedInStockVariantIds = { in_stock_variant_ids: [] };window._RestockRocketConfig.cachedOutOfStockVare_offer":false,"schedule_start_date":null,"schedule_end_date":null,"updated_at":"2025-08-19T10:05:43.042Z","allow_mixed_cart":true,"mixed_cart_error_message":"Preorders must be purchased separately from regular items. Please complete your current order first, or clear your cart to continue.","b2b_enabled":true,"preorder_progress_bar_enabled":false,"preorder_progress_bar_text":"{{ sold }} of {{ total }} claimed","preorder_progress_bar_fill_color":"#000000","preorder_progress_bar_background_color":"#e5e5e5","preorder_progress_bar_text_color":"#FFFFFF","preorder_progress_bar_border_radius":4,"preorder_progress_bar_show_percentage":false}],"disabled_plan_ids":[713813721471,713176482175],"cached_at":"2026-02-18T08:36:42Z"}; if (cachedData && typeof cachedData === 'object' && cachedData.cached_at) { // Find the maximum updated_at from all items in old array const oldPlans = window._RestockRocketConfig.sellingPlans; const maxUpdatedAt = Array.isArray(oldPlans) && oldPlans.length > 0 ? oldPlans.reduce(function(max, plan) { // Parse dates for proper comparison (handles mixed ISO formats) if (plan.updated_at) { const planDate = new Date(plan.updated_at); const maxDate = max ? new Date(max) : null; return (!maxDate || (planDate && !isNaN(planDate) && planDate > maxDate)) ? plan.updated_at : max; } return max; }, '') : null; // Use cached if old array is empty/has no timestamps, or cached is newer // Parse dates for comparison to handle format differences (+00:00 vs .000Z) const cachedDate = new Date(cachedData.cached_at); const maxDate = maxUpdatedAt ? new Date(maxUpdatedAt) : null; const useCached = !maxUpdatedAt || (cachedDate && !isNaN(cachedDate) && (!maxDate || cachedDate > maxDate)); if (useCached) { if (Array.isArray(cachedData.plans)) { window._RestockRocketConfig.sellingPlans = ca
  • chedData.plans; // Only use disabled_plan_ids when using cached plans window._RestockRocketConfig.disabledSellingPlanIds = cachedData.disabled_plan_ids || []; console.debug('[RR] Using selling plans from cachedSellingPlans (cached_at: ' + cachedData.cached_at + ')'); } } else { // When using old format (stale cache), don't trust disabled_plan_ids window._RestockRocketConfig.disabledSellingPlanIds = []; console.debug('[RR] Using selling plans from old format (max updated_at: ' + maxUpdatedAt + ')'); } } })();window._RestockRocketConfig.integrations = [{"id":"15c94526-b6b8-4de1-9bc1-23b1ca52ddb0","shop_id":38436,"enabled":true,"page_types":["product","collection","index","search","page","cart","list-collections","article","blog"],"configuration":{"toastDuration":10000,"toastPosition":"bottom-right","enableXHRHijack":true,"enableFetchHijack":true,"quantityLimitDisabled":false},"type":"hijack","css_config":null," Yes - you can come in store to hire a bike and can even pay with cash too! However, it would be best to js_config":null,"created_at":"2025-07-26T09:16:04.076Z","updated_at":"2025-07-26T09:16:04.076Z"}];window._RestockRocketConfig.obfuscateInventoryQuantity = false;window._RestockRocketConfig.product = {"id":8743146127586,"title":"AtranVelo Rainy Duo Cover Basket Rain Cover, With Window","handle":"atranvelo-rainy-duo-cover-basket-rain-cover-with-window","description":"\u003cul\u003e\n\u003cli\u003eThis handy accessory attaches easily to the DUO Basket and DUO Cover (sold separately) and features a convenient zipper that allows you to open and close it without any hassle.\u003c\/li\u003e\n\u003cli\u003eWith the DUO Raincover, you and your pup can enjoy your outdoor adventures together, even when the weather isn’t perfect.\u003c\/li\u003e\n\u003c\/ul\u003e\n\u003cul class=\"attributesSpecification\"\u003e\n\u003cli\u003e\n\u003cdiv class=\"label\"\u003eProduct Type\u003c\/div\u003e\n\u003cdiv class=\"value\"\u003eBag Covers\u003c\/div\u003e\n\u003c\/li\u003e\n\u003cli\u003e\n\u003cdiv class=\"label\"\u003eColour.333,"height":1350,"width":1800,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/av035_02.jpg?v=1729942850"},"aspect_ratio":1.333,"height":1350,"media_type":"image","src":"\/\/projektride.co.uk\/cdn\/shop\/files\/av035_02.jpg?v=1729942850","width":1800},{"alt":null,"id":34865756471522,"position":3,"preview_image":{"aspect_ratio":1.333,"height":1350,"width":1800,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/av035_03.jpg?v=1729942850"},"aspect_ratio":1.333,"height":1350,"media_type":"image","src":"\/\/projektride.co.uk\/cdn\/shop\/files\/av035_03.jpg?v=1729942850","width":1800}],"requires_selling_plan":false,"selling_plan_groups":[],"content":"\u003cul\u003e\n\u003cli\u003eThis handy accessory attaches easily to the DUO Basket and DUO Cover (sold separately) and features a convenient zipper that allows you to open and close it without any hassle.\u003c\/li\u003e\n\u003cli\u003eWith the DUO Raincover, you and your pup can enjoy your outdoor adventures together, even when the weather isn’t perfect.\u003c\/li\u call in advance to ensure we have a suitable bike for you to rent.003e\n\u003c\/ul\u003e\n\u003cul class=\"attributesSpecification\"\u003e\n\u003cli\u003e\n\u003cdiv class=\"label\"\u003eProduct Type\u003c\/div\u003e\n\u003cdiv class=\"value\"\u003eBag Covers\u003c\/div\u003e\n\u003c\/li\u003e\n\u003cli\u003e\n\u003cdiv class=\"label\"\u003eColour\u003c\/div\u003e\n\u003cdiv class=\"value\"\u003eBlack\u003c\/div\u003e\n\u003c\/li\u003e\n\u003cli\u003e\n\u003cdiv class=\"label\"\u003eSize\u003c\/div\u003e\n\u003cdiv class=\"value\"\u003eOne size\u003c\/div\u003e\n\u003c\/li\u003e\n\u003cli\u003e\n\u003cdiv class=\"label\"\u003eFeature\u003c\/div\u003e\n\u003cdiv class=\"value\"\u003eWaterproof\u003c\/div\u003e\n\u003c\/li\u003e\n\u003c\/ul\u003e"}; window._RestockRocketConfig.variantsInventoryPolicy = {46082016051426 : "deny",}; window._RestockRocketConfig.variantsInventoryQuantity = {46082016051426 : parseInt("1"),}; window._RestockRocketConfig.variantsPreorderCount = {46082016051426 : parseInt(""),}; window._RestockRocketConfig.variantsPreorderCountForMarke]; if (value !== null && value !== undefined && value !== '') { settings[key] = value; } }); } else { console.debug('STOQ - No translated fields found for locale:', normalizedLocale); } delete settings.translations; return settings; } catch (e) { console.debug('STOQ - error applying translations:', e); return settings; } } // Setup event listener for cart selling plan updates // This must be called before any scripts are loaded to avoid race conditions function setupCartSellingPlanUpdater(settings) { // Setup listener regardless - updateCartSellingPlans has its own guards // This ensures cleanup happens even when preorders are disabled globally // Listen for stoq:inventory-data-loaded event dispatched by api.js window.addEventListener('stoq:inventory-data-loaded', function(event) { console.debug('STOQ - Inventory data loaded, updating cart selling plans'); if (window._RestockRocket Yes && window._RestockRocket.updateCartSellingPlans) { window._RestockRocket.updateCartSellingPlans() .then(hasUpdates => { if (hasUpdates) { console.debug('STOQ - cart selling plans updated successfully'); } else { console.debug('STOQ - no cart selling plan updates needed'); } }) .catch(error => { console.error('STOQ - error updating cart selling plans:', error); }); } }); } // First try to get settings from metafields with expiry check const cachedSettings = window._RestockRocketConfig.cachedSettings; const validCachedSettings = cachedSettings ? checkSettingsExpiry(cachedSettings) : null; if (validCachedSettings) { console.debug('STOQ - using cached settings'); initializeScripts(validCachedSettings); } else { console.debug('STOQ - fetching fresh settings'); const headers = { 'X-Shopify-Shop-Domain': window._RestockRocketConfig.shop || window.S
  • hopify.shop, 'ngrok-skip-browser-warning': 'skip' }; if (window.Shopify?.theme?.role === 'main') { headers['X-Shopify-Theme-Schema-Name'] = window.Shopify.theme.schema_name; headers['X-Shopify-Theme-Schema-Version'] = window.Shopify.theme.schema_version; headers['X-Shopify-Theme-Store-Id'] = window.Shopify.theme.theme_store_id; } fetch( `${window._RestockRocketConfig.host}/api/v1/setting.json?translation_locale=${window._RestockRocketConfig.normalizedLocale}`, { headers } ) .then(function(response) { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(function(settings) { initializeScripts(settings); }) .catch(function(error) { // If request failed and we have cached settings (even if expired), use them as fallback if (cachedSettings) { console.debug('STOQ - using expired cached settings as fallback'); initializeScripts(cac Yes hedSettings); } else { console.error('STOQ - failed to load settings:', error); } }) .catch(function(e) { console.error(e) }) } function initializeScripts(settings) { settings = applyTranslations(settings); window._RestockRocketConfig.settings = settings; console.debug(`STOQ - settings configured for ${window._RestockRocketConfig.pageType}`); // Setup cart selling plan updater BEFORE loading any scripts to avoid race conditions setupCartSellingPlanUpdater(settings); if(settings.enable_app) { const hijackIntegration = window._RestockRocketConfig.integrations.find(function(integration) { return integration.type === 'hijack' && integration.enabled && integration.page_types.includes(window._RestockRocketConfig.pageType); }) if(window._RestockRocketConfig.pageType === 'collection' && (settings.show_button_on_collection || settings.preorder_collection_enabled)) { createRestockRocketScript(window._RestockRocketCon We like to keep things simple here at ProjektRide, we don't take any form of security deposit.
  • We like to keep things simple here at ProjektRide, we don't take any form of security deposit.If you happen to damage the bike, our insurance will cover it fully! We do ask for a valid passport document upon collection. If you are looking for a custom bike for your tour,
  • If you are looking for a custom bike for your tour, please get in touch . We can do full custom-builds at a higher rental rate. We are happy to keep your belongings safe, including suitcases etc. whilst you are out in one of our rental bikes.
  • We are happy to keep your belongings safe, including suitcases etc. whilst you are out in one of our rental bikes.
  • At what time do I need to return the bike? You must return your bike before the shop closes on your return date. Please review our working hours
  • hereYou must return your bike before the shop closes on your return date. Please review our working hours Bike Hire Terms & Conditions. Failure to do so in time may result in additional charges. Please see our .site-footer { --bg: #1f2324; --text: #ffffff; --text-alpha-15: rgba(255, 255, 255, 0.15); --text-alpha-60: rgba(255, 255, 255, 0.6); --text-alpha-85: rgba(255, 255, 255, 0.85); } .footer-content__logo__image { width: 170px; }
.site-footer { --bg: #1f2324; --text: #ffffff; --text-alpha-15: rgba(255, 255, 255, 0.15); --text-alpha-60: rgba(255, 255, 255, 0.6); --text-alpha-85: rgba(255, 255, 255, 0.85); } .footer-content__logo__image { width: 170px; }
age = Date.now() - updatedAt.getTime(); if (age translation data in metafield // Metafield hasn't been backfilled yet - force refresh console.debug('STOQ - multi-language enabled but no translation data in cache, fetching fresh'); return null; } // Translations object exists in metafield - cache is valid // If current locale isn't translated, applyTranslations will gracefully use default locale from base fields if (window._RestockRocketConfig.normalizedLocale && !Object.prototype.hasOwnProperty.call(settings.translations, window._RestockRocketConfig.normalizedLocale)) { console.debug('STOQ - locale not explicitly translated, will use default language from cache'); } // Don't return null - continue using cache even for untranslated locales } const updatedAt = new Date(settings.updated_at); if (isNaN(updatedAt.getTime())) { console.debug('STOQ - Invalid updated_at date format in settings'); return null; } const
!settings.multi_language_enabled) { return settings; } if (!settings.translations) { console.debug('STOQ - No translations found, skipping translation'); return settings; } const normalizedLocale = window._RestockRocketConfig.normalizedLocale; const translations = settings.translations; if (!normalizedLocale) { // No matching locale has translations; drop payload to save memory console.debug('STOQ - No matching locale for translations. Available:', Object.keys(translations || {})); delete settings.translations; return settings; } console.debug(`STOQ - Applying translations for normalized locale: ${normalizedLocale} (original: ${window._RestockRocketConfig.locale})`); const translatedFields = translations[normalizedLocale]; if (translatedFields && typeof translatedFields === 'object') { Object.keys(translatedFields).forEach(function(key) { const value = translatedFields[key SETTINGS_CACHE_DURATION) { console.debug('STOQ - settings changed recently, skipping cache'); return null; } return settings; } catch (error) { console.debug('STOQ - Error checking settings cache:', error); return null; } } function createRestockRocketContainer() { const restockRocketContainer = document.createElement('div'); restockRocketContainer.id = 'restock-rocket'; document.body.appendChild(restockRocketContainer); } function createRestockRocketScript(scriptUrl) { const restockRocketScriptElement = document.createElement('script'); restockRocketScriptElement.setAttribute('defer', 'defer'); restockRocketScriptElement.src = scriptUrl; document.body.appendChild(restockRocketScriptElement); } createRestockRocketContainer() console.debug('STOQ - extension activated') function applyTranslations(settings) { try { // Skip translation logic entirely if multi-language is not enabled if (!settings || ]; if (value !== null && value !== undefined && value !== '') { settings[key] = value; } }); } else { console.debug('STOQ - No translated fields found for locale:', normalizedLocale); } delete settings.translations; return settings; } catch (e) { console.debug('STOQ - error applying translations:', e); return settings; } } // Setup event listener for cart selling plan updates // This must be called before any scripts are loaded to avoid race conditions function setupCartSellingPlanUpdater(settings) { // Setup listener regardless - updateCartSellingPlans has its own guards // This ensures cleanup happens even when preorders are disabled globally // Listen for stoq:inventory-data-loaded event dispatched by api.js window.addEventListener('stoq:inventory-data-loaded', function(event) { console.debug('STOQ - Inventory data loaded, updating cart selling plans'); if (window._RestockRocket!settings.multi_language_enabled) { return settings; } if (!settings.translations) { console.debug('STOQ - No translations found, skipping translation'); return settings; } const normalizedLocale = window._RestockRocketConfig.normalizedLocale; const translations = settings.translations; if (!normalizedLocale) { // No matching locale has translations; drop payload to save memory console.debug('STOQ - No matching locale for translations. Available:', Object.keys(translations || {})); delete settings.translations; return settings; } console.debug(`STOQ - Applying translations for normalized locale: ${normalizedLocale} (original: ${window._RestockRocketConfig.locale})`); const translatedFields = translations[normalizedLocale]; if (translatedFields && typeof translatedFields === 'object') { Object.keys(translatedFields).forEach(function(key) { const value = translatedFields[key
&& window._RestockRocket.updateCartSellingPlans) { window._RestockRocket.updateCartSellingPlans() .then(hasUpdates => { if (hasUpdates) { console.debug('STOQ - cart selling plans updated successfully'); } else { console.debug('STOQ - no cart selling plan updates needed'); } }) .catch(error => { console.error('STOQ - error updating cart selling plans:', error); }); } }); } // First try to get settings from metafields with expiry check const cachedSettings = window._RestockRocketConfig.cachedSettings; const validCachedSettings = cachedSettings ? checkSettingsExpiry(cachedSettings) : null; if (validCachedSettings) { console.debug('STOQ - using cached settings'); initializeScripts(validCachedSettings); } else { console.debug('STOQ - fetching fresh settings'); const headers = { 'X-Shopify-Shop-Domain': window._RestockRocketConfig.shop || window.S]; if (value !== null && value !== undefined && value !== '') { settings[key] = value; } }); } else { console.debug('STOQ - No translated fields found for locale:', normalizedLocale); } delete settings.translations; return settings; } catch (e) { console.debug('STOQ - error applying translations:', e); return settings; } } // Setup event listener for cart selling plan updates // This must be called before any scripts are loaded to avoid race conditions function setupCartSellingPlanUpdater(settings) { // Setup listener regardless - updateCartSellingPlans has its own guards // This ensures cleanup happens even when preorders are disabled globally // Listen for stoq:inventory-data-loaded event dispatched by api.js window.addEventListener('stoq:inventory-data-loaded', function(event) { console.debug('STOQ - Inventory data loaded, updating cart selling plans'); if (window._RestockRocket hopify.shop, 'ngrok-skip-browser-warning': 'skip' }; if (window.Shopify?.theme?.role === 'main') { headers['X-Shopify-Theme-Schema-Name'] = window.Shopify.theme.schema_name; headers['X-Shopify-Theme-Schema-Version'] = window.Shopify.theme.schema_version; headers['X-Shopify-Theme-Store-Id'] = window.Shopify.theme.theme_store_id; } fetch( `${window._RestockRocketConfig.host}/api/v1/setting.json?translation_locale=${window._RestockRocketConfig.normalizedLocale}`, { headers } ) .then(function(response) { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(function(settings) { initializeScripts(settings); }) .catch(function(error) { // If request failed and we have cached settings (even if expired), use them as fallback if (cachedSettings) { console.debug('STOQ - using expired cached settings as fallback'); initializeScripts(cac && window._RestockRocket.updateCartSellingPlans) { window._RestockRocket.updateCartSellingPlans() .then(hasUpdates => { if (hasUpdates) { console.debug('STOQ - cart selling plans updated successfully'); } else { console.debug('STOQ - no cart selling plan updates needed'); } }) .catch(error => { console.error('STOQ - error updating cart selling plans:', error); }); } }); } // First try to get settings from metafields with expiry check const cachedSettings = window._RestockRocketConfig.cachedSettings; const validCachedSettings = cachedSettings ? checkSettingsExpiry(cachedSettings) : null; if (validCachedSettings) { console.debug('STOQ - using cached settings'); initializeScripts(validCachedSettings); } else { console.debug('STOQ - fetching fresh settings'); const headers = { 'X-Shopify-Shop-Domain': window._RestockRocketConfig.shop || window.S