PageSourceSearch

https://tesana.com/assets/GameAppStorePage-fgr-5Yis.js

js tesana.com collected 2026-10-09 22:40:54 UTC 96,397 bytes, 1 lines download raw bytes

1import{j as e}from"./vendor-motion-hRg_q8lq.js";import{u as j,d as _,s as Ve,y as Je,ae as Te,v as Xe,A as Ze,a5 as et,l as Q,b as tt}from"./index-BKzE8EQ8.js";import{useGameSettings as at}from"./GameSettingsLayout-D9S5c2Df.js";import{r as b,N as rt}from"./vendor-react-E98sgxjj.js";import{b as oe,u as st,a as G}from"./vendor-query-bOUN_gKe.js";import{du as k}from"./vendor-fa-Bn2dnpnC.js";import{S as nt,P as H,F as y,T as R,a as K,u as it,b as xe,c as ot,f as ee,d as O,R as te,C as lt}from"./useDraftWait-BZCHcKG7.js";const dt=["draft","ready","in_review","submitted","in_review_apple","live","blocked"];function le(a){return a!=="draft"&&a!=="blocked"}const pt=new Set(dt.filter(le)),Pe="Art, audio and code were generated with AI tools from the creator’s own prompts and descriptions. All generated content was created ahead of release and is shipped as finished assets; the game does not generate any content while it runs.",se=[{value:"games",label:"Games"},{value:"entertainment",label:"Entertainment"},{value:"education",label:"Education"},{value:"music",label:"Music"},{value:"photo_video",label:"Photo & Video"},{value:"productivity",label:"Productivity"},{value:"utilities",label:"Utilities"},{value:"graphics_design",label:"Graphics & Design"},{value:"social_networking",label:"Social Networking"},{value:"health_fitness",label:"Health & Fitness"},{value:"lifestyle",label:"Lifestyle"},{value:"reference",label:"Reference"},{value:"simulation",label:"Simulation"},{value:"sports",label:"Sports"},{value:"travel",label:"Travel"},{value:"trivia",label:"Trivia"}],Ce=[{value:"action",label:"Action"},{value:"adventure",label:"Adventure"},{value:"arcade",label:"Arcade"},{value:"board",label:"Board"},{value:"card",label:"Card"},{value:"casino",label:"Casino"},{value:"educational",label:"Educational"},{value:"family",label:"Family"},{value:"music",label:"Music"},{value:"puzzle",label:"Puzzle"},{value:"racing",label:"Racing"},{value:"role_playing",label:"Role Playing"},{value:"simulation",label:"Simulation"},{value:"sports",label:"Sports"},{value:"strategy",label:"Strategy"},{value:"trivia",label:"Trivia"},{value:"word",label:"Word"}],Re=["none","infrequent","frequent"],U=[{value:"unrestricted_web",label:"Unrestricted web access",group:"Capabilities",hint:"A browser or open-ended link the player can follow anywhere."},{value:"user_generated_content",label:"User-generated content",group:"Capabilities"},{value:"messaging_chat",label:"Messaging and chat",group:"Capabilities",hint:"Players can send each other messages."},{value:"social_media",label:"Social media",group:"Capabilities"},{value:"advertising",label:"Advertising",group:"Capabilities"},{value:"profanity",label:"Profanity or crude humour",group:"Mature themes"},{value:"horror",label:"Horror or fear themes",group:"Mature themes"},{value:"alcohol_tobacco_drugs",label:"Alcohol, tobacco or drug use",group:"Mature themes"},{value:"suggestive",label:"Mature or suggestive themes",group:"Mature themes"},{value:"sexual_content",label:"Sexual content or nudity",group:"Sexuality or nudity"},{value:"cartoon_violence",label:"Cartoon or fantasy violence",group:"Violence"},{value:"realistic_violence",label:"Realistic violence",group:"Violence"},{value:"weapons",label:"Guns or other weapons",group:"Violence"},{value:"medical_info",label:"Medical or treatment information",group:"Medical or wellness"},{value:"health_wellness",label:"Health and wellness topics",group:"Medical or wellness"},{value:"gambling",label:"Gambling",group:"Chance-based activities"},{value:"simulated_gambling",label:"Simulated gambling",group:"Chance-based activities"},{value:"loot_boxes",label:"Loot boxes",group:"Chance-based activities",hint:"Randomised in-app purchases. Sells coins or items in a mystery bundle."},{value:"contests",label:"Contests",group:"Chance-based activities"},{value:"parental_controls",label:"Parental controls",group:"In-app controls"},{value:"age_assurance",label:"Age assurance",group:"In-app controls"}],Ke=[{value:"exempt",label:"Only exempt encryption",hint:"HTTPS, standard OS encryption and similar. This is the answer for nearly every Tesana game — the game itself does not implement encryption."},{value:"none",label:"No encryption",hint:"The game makes no network calls at all and uses no encrypted storage."},{value:"uses_encryption",label:"Uses non-exempt encryption",hint:"The game implements its own encryption or bundles a library that does. Apple will ask for documentation."}],qe=[{value:"none",label:"The game sells nothing",hint:"No coins, no items, no subscription. The simplest listing to review."},{value:"coins_only",label:"The game sells coins",hint:"Apple requires these to be sold through In-App Purchase on iOS, at Apple’s commission. The publishing team will tell you what this adds."},{value:"external_only",label:"Purchases happen outside the app",hint:"The game is paid for on the web or on another store and does not sell anything inside the app."}],Ee=[{value:"ios_iphone",label:"iPhone",hint:"Requires a mobile build of the game."},{value:"ios_ipad",label:"iPad",hint:"Shares the iPhone build but needs its own screenshots."},{value:"macos",label:"Mac",hint:"The desktop build the Steam export already produces."},{value:"appletv",label:"Apple TV",hint:"Optional. Needs a controller-first layout."},{value:"visionos",label:"Apple Vision Pro",hint:"Optional. Needs a spatial layout."}],Le=[{name:'iPhone 6.9"',size:"1320 x 2868",portrait:"1320 x 2868",landscape:"2868 x 1320",forDevice:"ios_iphone",required:!0,note:"Required for every iPhone listing. Current-generation displays."},{name:'iPhone 6.5"',size:"1242 x 2688",portrait:"1242 x 2688",landscape:"2688 x 1242",forDevice:"ios_iphone",required:!1,note:'Older large displays. Tesana renders it from the 6.9" set where Apple accepts it.'},{name:'iPad 13"',size:"2064 x 2752",portrait:"2064 x 2752",landscape:"27
152 x 2064",forDevice:"ios_ipad",required:!0,note:"Required for every iPad listing."},{name:"Mac",size:"2880 x 1800",portrait:"2880 x 1800",landscape:"2880 x 1800",forDevice:"macos",required:!0,note:"Apple accepts 1280x800 up to 2880x1800. Tesana ships the largest."},{name:"Apple TV",size:"1920 x 1080",portrait:"1920 x 1080",landscape:"1920 x 1080",forDevice:"appletv",required:!0,note:"Required only if the listing includes Apple TV."}],q={minimum:3,maximum:10};function Oe(a){return Le.filter(t=>t.required&&a.includes(t.forDevice))}function ct(a,t){if(Oe(t).length===0)return null;if(a<q.minimum){const r=q.minimum-a;return`Apple requires at least ${q.minimum} screenshots — ${r} more needed.`}return a>q.maximum?`Apple accepts at most ${q.maximum} screenshots per device.`:null}const F=[{value:"name",label:"Name",group:"Contact info"},{value:"email",label:"Email address",group:"Contact info"},{value:"phone",label:"Phone number",group:"Contact info"},{value:"address",label:"Physical address",group:"Contact info"},{value:"other_contact",label:"Other user contact info",group:"Contact info"},{value:"health",label:"Health",group:"Health and fitness"},{value:"fitness",label:"Fitness",group:"Health and fitness"},{value:"payment_info",label:"Payment info",group:"Financial info",hint:"A coin purchase collects payment details. Apple handles the payment itself on iOS."},{value:"credit_info",label:"Credit info",group:"Financial info"},{value:"other_financial",label:"Other financial info",group:"Financial info"},{value:"precise_location",label:"Precise location",group:"Location"},{value:"coarse_location",label:"Coarse location",group:"Location"},{value:"sensitive_info",label:"Sensitive info",group:"Sensitive info"},{value:"contacts",label:"Contacts",group:"Contacts"},{value:"emails_messages",label:"Emails or text messages",group:"User content"},{value:"photos_videos",label:"Photos or videos",group:"User content"},{value:"audio_data",label:"Audio data",group:"User content"},{value:"gameplay_content",label:"Gameplay content",group:"User content"},{value:"customer_support",label:"Customer support",group:"User content"},{value:"other_user_content",label:"Other user content",group:"User content"},{value:"browsing_history",label:"Browsing history",group:"History"},{value:"search_history",label:"Search history",group:"History"},{value:"user_id",label:"User ID",group:"Identifiers",hint:"A Tesana account id or a game-scoped player id."},{value:"device_id",label:"Device ID",group:"Identifiers"},{value:"purchase_history",label:"Purchase history",group:"Purchases"},{value:"product_interaction",label:"Product interaction",group:"Usage data"},{value:"advertising_data",label:"Advertising data",group:"Usage data"},{value:"other_usage",label:"Other usage data",group:"Usage data"},{value:"crash_data",label:"Crash data",group:"Diagnostics"},{value:"performance_data",label:"Performance data",group:"Diagnostics"},{value:"other_diagnostics",label:"Other diagnostic data",group:"Diagnostics"},{value:"other_data",label:"Other data types",group:"Other"}],He=[{value:"third_party_ads",label:"Third-party advertising"},{value:"own_ads",label:"Developer’s advertising or marketing"},{value:"analytics",label:"Analytics"},{value:"personalization",label:"Product personalization"},{value:"functionality",label:"App functionality"},{value:"other",label:"Other purposes"}],Ie=[{value:"manual",labelKey:"gameSettings.appStore.release.manual",label:"I will release it myself",hintKey:"gameSettings.appStore.release.manualHint",hint:"Apple approves the listing and it stays held until you press release."},{value:"automatic",labelKey:"gameSettings.appStore.release.automatic",label:"Release as soon as Apple approves",hintKey:"gameSettings.appStore.release.automaticHint",hint:"The listing goes live the moment review passes."},{value:"scheduled",labelKey:"gameSettings.appStore.release.scheduled",label:"Release on a date",hintKey:"gameSettings.appStore.release.scheduledHint",hint:"Pick a date at least two days out. Apple will not hold it longer than that without another review."}],De=[{code:"en-US",label:"English (U.S.)"},{code:"ja",label:"Japanese"},{code:"ko",label:"Korean"},{code:"pt-BR",label:"Portuguese (Brazil)"},{code:"ru",label:"Russian"},{code:"zh-Hans",label:"Chinese (Simplified)"}],Y=[{step:1,labelKey:"gameSettings.appStore.step1.title",label:"App Store listing"},{step:2,labelKey:"gameSettings.appStore.step2.title",label:"Pricing and release"},{step:3,labelKey:"gameSettings.appStore.step3.title",label:"Age rating"},{step:4,labelKey:"gameSettings.appStore.step4.title",label:"Languages and devices"},{step:5,labelKey:"gameSettings.appStore.step5.title",label:"Privacy and compliance"},{step:6,labelKey:"gameSettings.appStore.step6.title",label:"Screenshots"},{step:7,labelKey:"gameSettings.appStore.step7.title",label:"Rights and handover"}];function ne(a){return`app-store-step-${a}`}const ie=[{value:"preparing",label:"Being prepared",blurb:"We're getting your game's App Store listing and artwork ready."},{value:"with_tesana",label:"With the Tesana publishing team",blurb:"The Tesana team has your game and is working through our publishing checks."},{value:"submitted",label:"Submitted to Apple",blurb:"Your game's build and listing have been sent to App Review."},{value:"in_review_apple",label:"Apple is reviewing it",blurb:"Apple has y
1our game and is testing it. This is usually the longest wait."},{value:"live",label:"Released on the App Store",blurb:"Your game is out — anyone can find it and play it on the App Store."}];function ut(a){return ie.findIndex(t=>t.value===a)}function V(a,t,i){const r=[],p=new Map;for(const o of a){const s=t(o);p.has(s)||(p.set(s,[]),r.push(s)),p.get(s).push(i(o))}return r.map(o=>({group:o,values:p.get(o)}))}function D({step:a,description:t,children:i,aside:r}){const{t:p}=j("game"),o=Y.find(l=>l.step===a),s=o?p(o.labelKey,o.label):"";return e.jsx(nt,{id:ne(a),step:a,title:s,description:t,aside:r,children:i})}function gt(){const{t:a}=j("game");return b.useCallback(t=>a(t.labelKey,t.label),[a])}function ht(){const[a,t]=b.useState(Y[0].step);b.useEffect(()=>{const r=Y.map(o=>document.getElementById(ne(o.step))).filter(Boolean);if(r.length===0)return;const p=new IntersectionObserver(o=>{const s=o.filter(u=>u.isIntersecting);if(s.length===0)return;const l=s.reduce((u,d)=>u.boundingClientRect.top<d.boundingClientRect.top?u:d),c=Number(l.target.id.slice(15));Number.isNaN(c)||t(c)},{rootMargin:"-10% 0px -80% 0px",threshold:0});return r.forEach(o=>p.observe(o)),()=>p.disconnect()},[]);const i=b.useCallback(r=>{document.getElementById(ne(r))?.scrollIntoView({behavior:"smooth",block:"start"}),t(r)},[]);return{activeStep:a,goToStep:i}}function ye({activeStep:a,onSelect:t,variant:i}){const r=gt(),{t:p}=j("game"),o=e.jsx("p",{className:"text-xs font-medium text-muted-foreground uppercase tracking-wider mb-3",children:p("gameSettings.appStore.onThisForm","On this form")}),s=Y.map(l=>{const c=a===l.step;return e.jsx("li",{children:e.jsxs("button",{type:"button",onClick:()=>t(l.step),"aria-current":c?"true":void 0,"data-testid":`app-store-nav-${l.step}`,className:_("flex w-full items-start gap-2 rounded-sm px-2 py-1.5 text-left text-xs leading-snug transition-colors cursor-pointer",c?"bg-foreground
1/8 text-foreground":"text-muted-foreground hover:bg-foreground/4 hover:text-foreground"),children:[e.jsx("span",{className:_("w-4 shrink-0 tabular-nums text-[10px] mt-px",c?"text-foreground":"text-muted-foreground/60"),children:l.step}),e.jsx("span",{className:"min-w-0",children:r(l)})]})},l.step)});return i==="list"?e.jsxs("nav",{"aria-label":p("gameSettings.appStore.onThisForm","On this form"),className:"lg:hidden mb-6 rounded-md border border-border bg-card p-3",children:[o,e.jsx("ol",{className:"space-y-0.5",children:s})]}):e.jsxs("nav",{"aria-label":p("gameSettings.appStore.onThisForm","On this form"),className:"hidden lg:block sticky top-[calc(var(--site-banner-height,0px)+1rem)] self-start w-44 shrink-0",children:[o,e.jsx("ol",{className:"space-y-0.5",children:s})]})}function Se(a,t={},i=[]){const r=new Set(a.ai_drafted_fields??[]),p=s=>r.has(s);return[{id:"age_answers",field:"age_answers",kind:"survey",labelKey:"gameSettings.appStore.review.ageQuestion",label:"What does your game contain?",helpKey:"gameSettings.appStore.review.ageHelp",help:'Apple derives the age rating from these answers, and shows the rating on the store page. Every one starts at "None" — go through the list and change the ones that apply. Apple cannot tell an unanswered question from a "no", so this has to be complete.',required:!0,proposal:bt(a),drafted:!1},{id:"privacy_entries",field:"privacy_entries",kind:"survey",labelKey:"gameSettings.appStore.review.privacyQuestion",label:"What data does your game collect?",helpKey:"gameSettings.appStore.review.privacyHelp",help:"This becomes the privacy label on your store page, and Apple holds you to it. A Tesana game with cloud saves or a coin shop is collecting something — the account id, the gameplay progress, the purchase history — so check those first, then the rest.",required:!0,proposal:xt(a),drafted:!1},{id:"has_ai_generated_content",field:"has_ai_generated_content",kind:"toggle",offIsAnswer:!0,labelKey:"gameSettings.appStore.review.aiQuestion",label:"Was any of this game generated by AI?",helpKey:"gameSettings.appStore.review.aiHelp",help:"Apple asks this on every submission. Tesana builds these games with generated art, audio and code, so the honest answer is usually yes — but it is your statement to Apple, so confirm it yourself.",required:!0,proposal:!0,drafted:!1},{id:"ai_content_disclosure",field:"ai_content_disclosure",kind:"textarea",labelKey:"gameSettings.appStore.review.aiDetailQuestion",label:"What was generated, and how?",helpKey:"gameSettings.appStore.review.aiDetailHelp",help:"Goes to App Review verbatim, so describe it plainly — which art, audio or text was generated, and whether it was made ahead of time or while the game runs.",required:!0,when:s=>(s.has_ai_generated_content??a.has_ai_generated_content)===!0,proposal:a.ai_content_disclosure||Pe,drafted:!1},{id:"app_name",field:"app_name",kind:"text",labelKey:"gameSettings.appStore.review.nameQuestion",label:"What is the app called on the App Store?",helpKey:"gameSettings.appStore.review.nameHelp",help:"Apple shows this under the icon in search and on the product page, and caps it at 30 characters. It can differ from the name in Studio.",required:!0,maxLength:30,proposal:a.app_name||"",drafted:p("app_name")},{id:"subtitle",field:"subtitle",kind:"text",autoGrow:!0,labelKey:"gameSettings.appStore.review.subtitleQuestion",label:"What one line sits under the name?",helpKey:"gameSettings.appStore.review.subtitleHelp",help:"At most 30 characters. It appears directly under the app name in search results and on the product page, so it is the second thing anyone reads.",required:!0,maxLength:30,proposal:a.subtitle,drafted:p("subtitle")},{id:"description",field:"description",kind:"textarea",labelKey:"gameSettings.appStore.review.descriptionQuestion",label:"Describe the game for the product page",helpKey:"gameSettings.appStore.review.descriptionHelp",help:"A few short paragraphs: what the player does, and why it is fun. Apple rejects a description that links out to another store or promises a feature the build does not have.",required:!0,proposal:a.description,drafted:p("description")},{id:"keywords",field:"keywords",kind:"text",labelKey:"gameSettings.appStore.review.keywordsQuestion",label:"Which words should people find it by?",helpKey:"gameSettings.appStore.review.keywordsHelp",help:"Comma-separated, at most 100 characters total — Apple counts them against one budget, so three long phrases use it all. Do not repeat the app name: Apple already indexes that.",required:!0,maxLength:100,proposal:a.keywords,drafted:p("keywords")},{id:"primary_category",field:"primary_category",kind:"single",labelKey:"gameSettings.appStore.review.categoryQuestion",label:"Where should Apple file it?",helpKey:"gameSettings.appStore.review.categoryHelp",help:"The category decides which charts the game can appear in, which is the only place a new game is discoverable without a search.",required:!0,options:se.map(s=>({value:s.value,labelKey:s.label,label:s.label})),proposal:a.primary_category||"games",drafted:p("primary_category")},{id:"game_subcategory",field:"game_subcategory",kind:"single",labelKey:"gameSettings.appStore.review.subcategoryQuestion",label:"Which kind of game is it?",helpKey:"gameSettings.appStore.review.subcategoryHelp",help:"Apple uses this 
1second level to place the game within Games, and it is what players browse by. Pick the one that fits best.",required:!0,when:s=>(s.primary_category??a.primary_category)==="games",options:Ce.map(s=>({value:s.value,labelKey:s.label,label:s.label})),proposal:a.game_subcategory,drafted:!1},{id:"support_url",field:"support_url",kind:"text",inputType:"url",labelKey:"gameSettings.appStore.review.supportQuestion",label:"Where do players get help?",helpKey:"gameSettings.appStore.review.supportHelp",help:"Apple will not accept a listing without a support page that loads and says how to reach you. It is the link under the app name on the product page.",required:!0,proposal:a.support_url,drafted:!1},{id:"privacy_policy_url",field:"privacy_policy_url",kind:"text",inputType:"url",labelKey:"gameSettings.appStore.review.privacyPolicyQuestion",label:"Where is the privacy policy?",helpKey:"gameSettings.appStore.review.privacyPolicyHelp",help:"Required for every app, and Apple checks that it loads and mentions the data your privacy label declares. A dead link is a rejection.",required:!0,proposal:a.privacy_policy_url,drafted:!1},{id:"copyright_line",field:"copyright_line",kind:"text",labelKey:"gameSettings.appStore.review.copyrightQuestion",label:"What copyright line should Apple print?",helpKey:"gameSettings.appStore.review.copyrightHelp",help:"The line shown in the footer of the product page, usually the year and the rights holder. Apple wants the owner of the work named, which for a Tesana game is you.",required:!0,proposal:a.copyright_line,drafted:!1},{id:"is_free",field:"is_free",kind:"toggle",offIsAnswer:!0,labelKey:"gameSettings.appStore.review.freeQuestion",label:"Is the game free to download?",helpKey:"gameSettings.appStore.review.freeHelp",help:"Free means anyone can install it at no charge. A free game can still sell coins inside it, which is the next question but one.",required:!0,proposal:a.is_free,drafted:!1},{id:"price_usd",field:"price_usd",kind:"money",labelKey:"gameSettings.appStore.review.priceQuestion",label:"What should it cost?",helpKey:"gameSettings.appStore.review.priceHelp",help:"In US dollars, for example 4.99. Apple converts this into every other region’s price and picks the nearest of its own tiers, so this is the only price you set.",required:!0,when:s=>(s.is_free??a.is_free)===!1,proposal:a.price_usd??"",drafted:!1,toPatch:s=>typeof s!="string"||s.trim()===""?null:s.trim()},{id:"release_option",field:"release_option",kind:"single",labelKey:"gameSettings.appStore.review.releaseQuestion",label:"How should the release be timed?",helpKey:"gameSettings.appStore.review.releaseHelp",help:"Once Apple approves the listing, someone has to let it out. Releasing it yourself is the usual choice — it means the game does not go live while you are asleep.",required:!0,options:Ie.map(s=>({value:s.value,labelKey:s.labelKey,label:s.label,hint:s.hint})),proposal:a.release_option,drafted:!1},{id:"release_date",field:"release_date",kind:"text",inputType:"date",labelKey:"gameSettings.appStore.review.dateQuestion",label:"What date should it go live?",helpKey:"gameSettings.appStore.review.dateHelp",help:"At least two days out. Apple will not hold a scheduled listing longer than that without putting it through another review, so a date inside that window cannot be served.",required:!0,when:s=>(s.release_option??a.release_option)==="scheduled",proposal:a.release_date??"",drafted:!1},{id:"devices",field:"devices",kind:"chips",labelKey:"gameSettings.appStore.review.devicesQuestion",label:"Which devices should the game run on?",helpKey:"gameSettings.appStore.review.devicesHelp",help:"Each device adds a build to maintain and its own required set of screenshots. Mac is the build the desktop export already produces; iPhone and iPad need a mobile build of the game.",required:!0,options:Ee.map(s=>({value:s.value,labelKey:s.label,label:s.label,hint:s.hint})),proposal:a.devices,drafted:p("devices")},{id:"supported_languages",field:"supported_languages",kind:"chips",labelKey:"gameSettings.appStore.review.languageQuestion",label:"What languages does the listing support?",helpKey:"gameSettings.appStore.review.languageHelp",help:"English is already filled in. Add anything else the listing is translated into — Apple shows the app to players in each of these languages. Claiming one you do not have produces one-star reviews.",required:!0,options:De.map(s=>({value:s.code,labelKey:s.label,label:s.label})),proposal:mt(a),drafted:!1,toPatch:ft}
1,{id:"export_compliance",field:"export_compliance",kind:"single",labelKey:"gameSettings.appStore.review.exportQuestion",label:"Does the game use encryption?",helpKey:"gameSettings.appStore.review.exportHelp",help:'Apple asks every submission, even a game that makes no network calls at all. "Only exempt encryption" is the answer for nearly every Tesana game — the game itself does not implement any, it just talks over HTTPS.',required:!0,options:Ke.map(s=>({value:s.value,labelKey:s.label,label:s.label,hint:s.hint})),proposal:a.export_compliance,drafted:!1},{id:"iap_option",field:"iap_option",kind:"single",labelKey:"gameSettings.appStore.review.iapQuestion",label:"Does the game sell anything inside the app?",helpKey:"gameSettings.appStore.review.iapHelp",help:"This is the answer that changes what the listing *is*. Apple requires digital goods sold inside an app to be sold through In-App Purchase, at Apple’s commission — so a game with a coin shop cannot keep using Stripe on iOS.",required:!0,options:qe.map(s=>({value:s.value,labelKey:s.label,label:s.label,hint:s.hint})),proposal:a.iap_option,drafted:p("iap_option")},{id:"iap_notes",field:"iap_notes",kind:"textarea",labelKey:"gameSettings.appStore.review.iapNotesQuestion",label:"What does the game sell?",helpKey:"gameSettings.appStore.review.iapNotesHelp",help:"What the coins buy, and whether anything is consumable. This goes into the review notes so Apple’s reviewer knows what to look for, and it is what the publishing team reads to work out the StoreKit side.",required:!0,when:s=>(s.iap_option??a.iap_option)==="coins_only",proposal:a.iap_notes,drafted:p("iap_notes")},{id:"tracking_enabled",field:"tracking_enabled",kind:"toggle",offIsAnswer:!0,labelKey:"gameSettings.appStore.review.trackingQuestion",label:"Does the game track players across other apps?",helpKey:"gameSettings.appStore.review.trackingHelp",help:"Tracking means following a player into other companies’ apps or websites to target advertising. Almost every Tesana game is no — and turning it on requires Apple’s permission prompt before anything is tracked.",required:!0,proposal:a.tracking_enabled,drafted:!1},{id:"data_deletion_url",field:"data_deletion_url",kind:"text",inputType:"url",labelKey:"gameSettings.appStore.review.deletionQuestion",label:"Where can a player ask for their data to be deleted?",helpKey:"gameSettings.appStore.review.deletionHelp",help:"Required by Apple once the game has an account, which a Tesana game does as soon as it has saves. Leave it blank only if the game genuinely has no account and no stored data.",proposal:a.data_deletion_url,drafted:!1},{id:"screenshot_ids",field:"screenshot_ids",kind:"screenshots",labelKey:"gameSettings.appStore.review.shotsQuestion",label:"Which screenshots should go on the product page?",helpKey:"gameSettings.appStore.review.shotsHelp",help:"The first two are what Apple shows in search results, so lead with the one that explains the game fastest. Apple needs at least three, and builds the per-device sizes from these.",required:i.length>=q.minimum,min:q.minimum,proposal:i.map(s=>String(s.id)),drafted:!1,toPatch:s=>Array.isArray(s)?s.map(Number).filter(l=>!Number.isNaN(l)):[]},{id:"demo_account_required",field:"demo_account_required",kind:"toggle",offIsAnswer:!0,labelKey:"gameSettings.appStore.review.demoQuestion",label:"Does Apple need an account to try the game?",helpKey:"gameSettings.appStore.review.demoHelp",help:"App Review tests every submission, and an app behind a sign-in wall without a working demo account is rejected on sight. A Tesana game plays without signing in, so the answer is usually no — worth confirming rather than assuming.",required:!0,proposal:a.demo_account_required,drafted:!1},{id:"demo_account_details",field:"demo_account_details",kind:"textarea",labelKey:"gameSettings.appStore.review.demoDetail
1sQuestion",label:"What sign-in should the reviewer use?",helpKey:"gameSettings.appStore.review.demoDetailsHelp",help:"A working username and password, and any step needed to reach the part of the game you want reviewed. These go to App Review and are not shown anywhere public.",required:!0,when:s=>(s.demo_account_required??a.demo_account_required)===!0,proposal:a.demo_account_details,drafted:!1},{id:"review_notes",field:"review_notes",kind:"textarea",labelKey:"gameSettings.appStore.review.notesQuestion",label:"Anything the reviewer should know?",helpKey:"gameSettings.appStore.review.notesHelp",help:"Tell App Review about anything non-obvious — an unusual control, a feature that looks like something it is not, anything that needs explaining. A reviewer who cannot find a feature rejects the app rather than asking.",proposal:a.review_notes,drafted:p("review_notes")},{id:"content_rights_confirmed",field:"content_rights_confirmed",kind:"toggle",labelKey:"gameSettings.appStore.review.contentRightsQuestion",label:"This game contains no third-party content used without permission?",helpKey:"gameSettings.appStore.review.contentRightsHelp",help:"Apple rejects an app for artwork or audio it does not recognise the rights to. Covers music, art, fonts, names and any third-party code.",required:!0,proposal:!0,drafted:!1},{id:"rights_confirmed",field:"rights_confirmed",kind:"toggle",labelKey:"gameSettings.appStore.review.rightsQuestion",label:"Do you have the rights to everything in this game?",helpKey:"gameSettings.appStore.review.rightsHelp",help:"That covers the art, the audio, the name and any third-party content. Tesana publishes this under your name on the App Store, so we need your word before we do.",required:!0,proposal:!0,drafted:!1}].filter(s=>!(s.when&&!(s.when(t)||yt(a,s.field))))}function mt(a){const t=(a.supported_languages??[]).map(i=>
1i.code).filter(Boolean);return t.length>0?t:["en-US"]}function ft(a){return(Array.isArray(a)?a:[]).map(i=>({code:i,store_listing:!0,in_game:!0}))}function bt(a){const t=new Map((a.age_answers??[]).map(i=>[i.topic,i.frequency]));return U.map(i=>({topic:i.value,frequency:t.get(i.value)??"none"}))}function xt(a){const t=new Map((a.privacy_entries??[]).map(i=>[i.type,i]));return F.map(i=>t.get(i.value)??{type:i.value,collected:!1,linked_to_identity:!1,used_for_tracking:!1,purposes:[]})}function yt(a,t){const i=a[t];return Array.isArray(i)?i.length>0:typeof i=="string"?i.trim()!=="":typeof i=="boolean"?i:i!=null}function St(a,t){const i={};for(const r of a){if(!(r.id in t))continue;const p=t[r.id],o=r.field;if(r.toPatch){i[o]=r.toPatch(p);continue}if(r.kind==="chips"){i[o]=Array.isArray(p)?p:[];continue}if(r.kind==="toggle"){i[o]=p===!0;continue}typeof p=="string"&&p.trim()===""||(i[o]=p)}return i}function vt(a,t){if(Array.isArray(a)||Array.isArray(t)){const i=Array.isArray(a)?a:[],r=Array.isArray(t)?t:[];return i.length!==r.length?!1:i.every((p,o)=>JSON.stringify(p)===JSON.stringify(r[o]))}return a===t}function Ue(a,t){return a.kind==="toggle"?a.offIsAnswer?t!==void 0:t===!0:a.kind==="money"?!0:Array.isArray(t)?t.length>=(a.min??1):typeof t=="string"&&t.trim()!==""}function wt(a,t){return a.findIndex(i=>i.required&&!Ue(i,t[i.id]))}function Fe(a,t){if(a.kind!=="survey")return{answered:0,total:0};const i=Array.isArray(t)?t:[],r=a.field==="age_answers"?U.length:F.length;return{answered:i.filter(o=>{if(a.field==="age_answers")return typeof o.frequency=="string";const s=o;return!s.collected||(s.purposes?.length??0)>0}).length,total:r}}function _t({details:a,screenshots:t,onScreenshotUpload:i,uploadingScreenshot:r,onSubmit:p,submitting:o,error:s}){const{t:l}=j("game"),[c,u]=b.useState({}),[d,m]=b.useState({}),[h,f]=b.useState(null),[x,v]=b.useState(!1),S=b.useMemo(()=>Se(a,c,t),[a,c,t]);b.useEffect(()=>{u(T=>{let w=!1;const E={...T};for(const C of S)d[C.id]||vt(E[C.id],C.proposal)||(E[C.id]=C.proposal,w=!0);return w?E:T})},[S,d]);const N=h===null?0:Math.max(0,S.findIndex(T=>T.id===h)),P=S[N]??null,A=wt(S,c),g=N>=S.length-1,I=b.useCallback((T,w)=>{m(E=>E[T]?E:{...E,[T]:!0}),u(E=>({...E,[T]:w}))},[]),L=b.useRef(1),M=b.useCallback(()=>{L.current=1,N<S.length-1?f(S[N+1].id):v(!0)},[N,S]),W=b.useCallback(()=>{L.current=-1,x?v(!1):N>0&&f(S[N-1].id)},[N,S,x]),$=b.useCallback(async()=>{try{await p(St(Se(a,c,t),c))}catch{}},[c,a,t,p]),z=P?Ue(P,c[P.id]):!1;return x?e.jsx("div",{className:"animate-steam-question-in w-full",style:{"--steam-q":L.current},children:e.jsxs("div",{className:"rounded-md border border-border bg-card p-8",children:[e.jsx("h2",{className:"text-base font-medium text-foreground mb-2",children:l("gameSettings.appStore.review.doneHeading","That is everything we need from you")}),e.jsx("p",{className:"text-sm text-muted-foreground leading-relaxed mb-6",children:l("gameSettings.appStore.review.doneBody","We will use these answers to prepare your App Store listing. You can change any of it afterwards — the full form opens as soon as you finish here.")}),e.jsx("dl",{className:"space-y-3 mb-6",children:S.map(T=>e.jsxs("div",{className:"flex items-baseline justify-between gap-4",children:[e.jsx("dt",{className:"text-sm text-muted-foreground",children:l(T.labelKey,T.label)}),e.jsx("dd",{className:"text-sm text-foreground text-right min-w-0 truncate max-w-[60%]",children:Tt(T,c[T.id],l)})]},T.id))}),A>=0&&e.jsx(H,{tone:"warn",children:l("gameSettings.appStore.review.stillOpen","One answer is still needed: {{question}}",{question:l(S[A].labelKey,S[A].label)})}),s&&e.jsx(H,{tone:"warn",children:s}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{type:"button",onClick:W,disabled:o,className:"h-9 px-3 rounded-md text-sm text-muted-foreground hover:text-foreground transition-colors cursor-pointer disabled:opacity-50",children:l("gameSettings.appStore.review.back","Back")}),e.jsx("div",{className:"flex-1"}),e.jsxs("button",{type:"button",onClick:$,disabled:o||A>=0,className:"h-9 px-4 rounded-md bg-foreground text-background text-sm hover:opacity-80 transition-opacity disabled:opacity-30 curs
1or-pointer flex items-center gap-2",children:[o?l("gameSettings.appStore.review.saving","Saving…"):l("gameSettings.appStore.review.finish","Finish and open the form"),!o&&e.jsx(k,{icon:["far","arrow-right"],className:"text-xs"})]})]})]})}):P?e.jsx("div",{className:"w-full","data-testid":"app-store-initial-review",children:e.jsxs("div",{style:{"--steam-q":L.current},className:"animate-steam-question-in rounded-md border border-border bg-card p-8",children:[e.jsx(jt,{question:P,value:c[P.id],screenshots:t,onChange:T=>I(P.id,T),onScreenshotUpload:i,uploadingScreenshot:r}),s&&e.jsx(H,{tone:"warn",children:s}),e.jsxs("div",{className:"mt-6 flex items-center gap-2",children:[N>0?e.jsx("button",{type:"button",onClick:W,disabled:o,className:"h-9 px-3 rounded-md bg-foreground/6 text-foreground text-sm hover:bg-foreground/10 transition-colors cursor-pointer disabled:opacity-50",children:l("gameSettings.appStore.review.back","Back")}):e.jsx("span",{}),e.jsx("div",{className:"flex-1"}),e.jsxs("button",{type:"button",onClick:M,disabled:!z&&!!P.required&&!g||o,className:"h-9 px-4 rounded-md bg-foreground text-background text-sm hover:opacity-80 transition-opacity disabled:opacity-30 cursor-pointer flex items-center gap-2",children:[g?l("gameSettings.appStore.review.review","Review"):l("gameSettings.appStore.review.next","Next"),e.jsx(k,{icon:["far","arrow-right"],className:"text-xs"})]})]}),e.jsxs("div",{className:"mt-6 pt-4 border-t border-border flex items-center gap-3",children:[e.jsx("div",{className:"h-1 flex-1 rounded-full bg-foreground
1/8 overflow-hidden",children:e.jsx("div",{className:"h-full rounded-full bg-accent transition-all",style:{width:`${S.length?(N+1)/S.length*100:0}%`}})}),e.jsx("span",{className:"text-[11px] text-muted-foreground tabular-nums shrink-0",children:l("gameSettings.appStore.review.step","Question {{current}} of {{total}}",{current:N+1,total:S.length})})]})]},P.id)}):null}function jt({question:a,value:t,screenshots:i,onChange:r,onScreenshotUpload:p,uploadingScreenshot:o}){const{t:s}=j("game"),l=s(a.labelKey,a.label),c=s(a.helpKey,a.help),u=a.drafted&&e.jsxs("span",{className:"inline-flex items-center gap-1 text-[10px] uppercase tracking-wide text-accent bg-accent/10 rounded-full px-2 py-0.5 ml-2 align-middle",children:[e.jsx(k,{icon:["far","wand-magic-sparkles"],className:"text-[9px]"}),s("gameSettings.appStore.review.drafted","AI draft — check it")]});return e.jsxs("div",{children:[e.jsxs("h2",{className:"text-base font-medium text-foreground mb-2",children:[l,a.required&&e.jsx("span",{className:"text-accent ml-1",children:"*"}),u]}),e.jsx("p",{className:"text-sm text-muted-foreground leading-relaxed mb-5",children:c}),a.kind==="survey"&&e.jsx(H,{tone:"warn",children:s("gameSettings.appStore.review.surveyNotice","This is your declaration to Apple, so we have left every answer for you to confirm. Nothing here was filled in on your behalf.")}),a.kind==="toggle"?e.jsx("div",{className:"flex gap-2",children:[{on:!0,labelKey:"gameSettings.appStore.review.yes",label:"Yes"},{on:!1,labelKey:"gameSettings.appStore.review.no",label:"No"}].map(d=>e.jsx("button",{type:"button","aria-pressed":t===d.on,onClick:()=>r(d.on),className:_("px-5 h-10 rounded-md border text-sm transition-colors cursor-pointer",t===d.on?"border-accent/50 bg-accent/10 text-accent":"border-border bg-foreground
1/3 text-muted-foreground hover:text-foreground"),children:s(d.labelKey,d.label)},String(d.on)))}):a.kind==="survey"?e.jsx(kt,{question:a,value:t,onChange:r}):a.kind==="single"?e.jsx("div",{className:"space-y-1.5",children:(a.options??[]).map(d=>e.jsx("button",{type:"button","aria-pressed":t===d.value,onClick:()=>r(d.value),className:_("w-full text-left px-3 py-2.5 rounded-md border text-sm transition-colors cursor-pointer",t===d.value?"border-accent/50 bg-accent/8 text-foreground":"border-border bg-foreground/3 text-muted-foreground hover:text-foreground"),children:s(d.labelKey,d.label)},d.value))}):a.kind==="chips"?e.jsx(At,{question:a,value:Array.isArray(t)?t:[],onChange:r}):a.kind==="screenshots"?e.jsx(Nt,{screenshots:i,value:Array.isArray(t)?t:[],onChange:d=>r(d),onUpload:p,uploading:o}):a.kind==="textarea"?e.jsx(y,{label:"",children:e.jsx(R,{value:typeof t=="string"?t:"",onChange:r,rows:7,placeholder:s("gameSettings.appStore.review.longPlaceholder","A few short paragraphs…")})}):a.kind==="money"?e.jsx(y,{label:"",children:e.jsx(K,{type:"number",value:typeof t=="string"?t:"",onChange:r,placeholder:s("gameSettings.appStore.review.pricePlaceholder","e.g. 4.99")})}):a.autoGrow?e.jsx(y,{label:"",children:e.jsx(R,{value:typeof t=="string"?t:"",onChange:r,rows:2,autoGrow:!0,maxLength:a.maxLength})}):e.jsx(y,{label:"",children:e.jsx(K,{type:a.inputType??"text",value:typeof t=="string"?t:"",onChange:r,maxLength:a.inputType==="date"?void 0:a.maxLength??32})})]})}function kt({question:a,value:t,onChange:i}){const{t:r}=j("game"),p=Fe(a,t);if(a.field==="age_answers"){const c=Array.isArray(t)?t:[],u=V(U,d=>d.group,d=>d.value);return e.jsxs("div",{children:[e.jsx(ve,{...p}),e.jsx("div",{className:"space-y-5",children:u.map(d=>e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] uppercase tracking-wide text-muted-foreground/60 mb-2",children:d.group}),e.jsx("div",{className:"space-y-2",children:d.values.map(m=>{const h=U.find(v=>v.value===m),x=c.find(v=>v.topic===m)?.frequency??"none";return e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs("span",{className:"text-sm text-foreground min-w-0 flex-1",children:[h.label,h.hint&&e.jsx("span",{className:"block text-[11px] text-muted-foreground mt-0.5",children:h.hint})]}),e.jsx("div",{className:"flex gap-1 shrink-0",children:Re.map(v=>e.jsx("button",{type:"button","aria-pressed":x===v,onClick:()=>i(c.map(S=>S.topic===m?{...S,frequency:v}:S)),className:_("px-2.5 py-1 rounded-md text-[11px] border transition-colors cursor-pointer capitalize",x===v?"border-accent/40 bg-accent/15 text-accent":"border-border bg-foreground
1/3 text-muted-foreground hover:text-foreground"),children:r(`gameSettings.appStore.frequency.${v}`,v)},v))})]},m)})})]},d.group))})]})}const o=Array.isArray(t)?t:[],s=V(F,c=>c.group,c=>c.value),l=(c,u)=>i(o.map(d=>d.type===c?{...d,...u}:d));return e.jsxs("div",{children:[e.jsx(ve,{...p}),e.jsx("div",{className:"space-y-5",children:s.map(c=>e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] uppercase tracking-wide text-muted-foreground/60 mb-2",children:c.group}),e.jsx("div",{className:"space-y-2",children:c.values.map(u=>{const d=F.find(h=>h.value===u),m=o.find(h=>h.type===u)??{collected:!1,linked_to_identity:!1,used_for_tracking:!1,purposes:[]};return e.jsxs("div",{className:"rounded-md border border-border p-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs("span",{className:"text-sm text-foreground min-w-0 flex-1",children:[d?.label??u,d?.hint&&e.jsx("span",{className:"block text-[11px] text-muted-foreground mt-0.5",children:d.hint})]}),e.jsx("div",{className:"flex gap-1 shrink-0",children:[{on:!1,labelKey:"gameSettings.appStore.review.notCollected",label:"Not collected"},{on:!0,labelKey:"gameSettings.appStore.review.collected",label:"Collected"}].map(h=>e.jsx("button",{type:"button","aria-pressed":m.collected===h.on,onClick:()=>l(u,h.on?{collected:!0}:{collected:!1,linked_to_identity:!1,used_for_tracking:!1,purposes:[]}),className:_("px-2.5 py-1 rounded-md text-[11px] border transition-colors cursor-pointer",m.collected===h.on?"border-accent/40 bg-accent/15 text-accent":"border-border bg-foreground
1/3 text-muted-foreground hover:text-foreground"),children:r(h.labelKey,h.label)},String(h.on)))})]}),m.collected&&e.jsxs("div",{className:"mt-3 pl-3 border-l border-border space-y-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("span",{className:"text-xs text-muted-foreground min-w-0 flex-1",children:r("gameSettings.appStore.review.linkedQuestion","Is this linked to the player’s identity?")}),e.jsx("div",{className:"flex gap-1 shrink-0",children:[!0,!1].map(h=>e.jsx("button",{type:"button","aria-pressed":m.linked_to_identity===h,onClick:()=>l(u,{linked_to_identity:h}),className:_("px-2.5 py-1 rounded-md text-[11px] border transition-colors cursor-pointer",m.linked_to_identity===h?"border-accent/40 bg-accent/15 text-accent":"border-border bg-foreground/3 text-muted-foreground hover:text-foreground"),children:h?r("gameSettings.appStore.review.yes","Yes"):r("gameSettings.appStore.review.no","No")},String(h)))})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("span",{className:"text-xs text-muted-foreground min-w-0 flex-1",children:r("gameSettings.appStore.review.trackingDataQuestion","Is it used for tracking?")}),e.jsx("div",{className:"flex gap-1 shrink-0",children:[!0,!1].map(h=>e.jsx("button",{type:"button","aria-pressed":m.used_for_tracking===h,onClick:()=>l(u,{used_for_tracking:h}),className:_("px-2.5 py-1 rounded-md text-[11px] border transition-colors cursor-pointer",m.used_for_tracking===h?"border-accent/40 bg-accent/15 text-accent":"border-border bg-foreground
1/3 text-muted-foreground hover:text-foreground"),children:h?r("gameSettings.appStore.review.yes","Yes"):r("gameSettings.appStore.review.no","No")},String(h)))})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-xs text-muted-foreground mb-2",children:r("gameSettings.appStore.review.purposesQuestion","Why is it collected? Pick at least one.")}),e.jsx("div",{className:"flex flex-wrap gap-1.5",children:He.map(h=>{const f=m.purposes.includes(h.value);return e.jsx("button",{type:"button","aria-pressed":f,onClick:()=>l(u,{purposes:f?m.purposes.filter(x=>x!==h.value):[...m.purposes,h.value]}),className:_("px-2.5 py-1 rounded-md text-[11px] border transition-colors cursor-pointer",f?"border-accent/40 bg-accent/15 text-accent":"border-border bg-foreground/3 text-muted-foreground hover:text-foreground"),children:r(`gameSettings.appStore.privacyPurpose.${h.value}`,h.label)},h.value)})})]})]})]},u)})})]},c.group))})]})}function ve({answered:a,total:t}){const{t:i}=j("game");return e.jsxs("div",{className:"mb-4 flex items-center gap-3",children:[e.jsx("div",{className:"h-1 flex-1 rounded-full bg-foreground
1/8 overflow-hidden",children:e.jsx("div",{className:"h-full rounded-full bg-accent transition-all",style:{width:`${t?a/t*100:0}%`}})}),e.jsx("span",{className:"text-[11px] text-muted-foreground tabular-nums shrink-0",children:i("gameSettings.appStore.review.surveyProgress","{{answered}} of {{total}} answered",{answered:a,total:t})})]})}function Nt({screenshots:a,value:t,onChange:i,onUpload:r,uploading:p}){const{t:o}=j("game"),s=b.useRef(null),[l,c]=b.useState(""),u=Math.max(0,q.minimum-t.length),d=a.length>=6,m=f=>{const x=f.target.files?.[0];if(s.current&&(s.current.value=""),!!x){if(!x.type.startsWith("image/")){c(o("gameSettings.screenshots.selectImage","Please select an image file."));return}if(x.size>5*1024*1024){c(o("gameSettings.screenshots.imageTooLarge","Image must be under 5MB."));return}c(""),r(x).then(v=>{v&&i([...t,String(v.id)])})}},h=f=>i(t.includes(f)?t.filter(x=>x!==f):[...t,f]);return e.jsxs("div",{children:[a.length===0&&e.jsx(H,{tone:"warn",children:o("gameSettings.appStore.review.shotsNone","This game has no screenshots yet. Add at least {{count}} here — Apple will not accept a product page without them.",{count:q.minimum})}),e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-3 gap-2",children:[e.jsx("button",{type:"button",onClick:()=>s.current?.click(),disabled:p||d,className:_("flex flex-col items-center justify-center gap-1 aspect-video rounded-md border border-dashed border-border transition-colors cursor-pointer","text-muted-foreground hover:text-foreground hover:border-foreground
1/30","disabled:opacity-40 disabled:cursor-not-allowed"),children:p?e.jsxs(e.Fragment,{children:[e.jsx(k,{icon:["far","spinner"],spin:!0,className:"text-base"}),e.jsx("span",{className:"text-[10px]",children:o("gameSettings.screenshots.uploading","Uploading…")})]}):e.jsxs(e.Fragment,{children:[e.jsx(k,{icon:["far","plus"],className:"text-base"}),e.jsx("span",{className:"text-[10px]",children:d?o("gameSettings.screenshots.limitReached","Maximum 6 screenshots"):o("gameSettings.appStore.review.shotsAdd","Add a screenshot")})]})}),a.map(f=>{const x=t.includes(String(f.id));return e.jsxs("button",{type:"button","aria-pressed":x,onClick:()=>h(String(f.id)),className:_("relative aspect-video rounded-md overflow-hidden border-2 transition-all cursor-pointer",x?"border-accent":"border-transparent opacity-60 hover:opacity-100"),children:[e.jsx("img",{src:f.image,alt:f.caption||"",className:"w-full h-full object-cover"}),x&&e.jsx("span",{className:"absolute top-1 right-1 w-5 h-5 rounded-full bg-accent text-accent-foreground flex items-center justify-center",children:e.jsx(k,{icon:["far","check"],className:"text-[10px]"})})]},f.id)})]}),e.jsx("input",{ref:s,type:"file",accept:"image/*",onChange:m,className:"hidden"}),l&&e.jsx("p",{className:"text-[11px] text-destructive mt-2",children:l}),u>0&&e.jsx("div",{className:"mt-3",children:e.jsx(H,{tone:"warn",children:o("gameSettings.appStore.review.shotsMore","Apple needs at least {{count}} — choose {{missing}} more.",{count:q.minimum,missing:u})})})]})}function At({question:a,value:t,onChange:i}){const{t:r}=j("game"),p=a.max!==void 0&&t.length>=a.max,o=s=>{if(t.includes(s)){i(t.filter(l=>l!==s));return}p||i([...t,s])};return e.jsx("div",{className:"flex flex-wrap gap-1.5",children:(a.options??[]).map(s=>{const l=t.includes(s.value),c=!l&&p;return e.jsx("button",{type:"button",title:s.hint,"aria-pressed":l,disabled:c,onClick:()=>o(s.value),className:_("px-2.5 py-1.5 rounded-md text-xs border transition-colors",l?"bg-accent/15 border-accent/40 text-accent":"bg-foreground
1/5 border-border text-muted-foreground hover:text-foreground hover:border-foreground/30",c?"cursor-not-allowed opacity-40":"cursor-pointer"),children:r(s.labelKey,s.label)},s.value)})})}function Tt(a,t,i){if(a.kind==="toggle")return t===!0?i("gameSettings.appStore.review.yes","Yes"):i("gameSettings.appStore.review.no","No");if(a.kind==="money")return typeof t=="string"&&t.trim()!==""?`$${t.trim()}`:i("gameSettings.appStore.review.free","Free");if(a.kind==="survey"){const r=Fe(a,t);return i("gameSettings.appStore.review.surveySummary","{{answered}} of {{total}} answered",{answered:r.answered,total:r.total})}if(Array.isArray(t)&&t.length>0&&typeof t[0]=="object")return i("gameSettings.appStore.review.answered","Answered");if(Array.isArray(t))return a.kind==="screenshots"?i("gameSettings.appStore.review.shotsChosen","{{count}} selected",{count:t.length}):t.map(p=>a.options?.find(o=>o.value===p)?.label??p).join(", ");if(typeof t=="string"){const r=a.options?.find(p=>p.value===t);return r?i(r.labelKey,r.label):t}return""}function Pt(a){const t=a/100;return t%1===0?`$${t.toFixed(0)}`:`$${t.toFixed(2)}`}function Ct({game:a,access:t}){const{t:i}=j("game"),r=oe(),[p,o]=b.useState(!1),s=`${window.location.pathname}?purchased=true`,l=encodeURIComponent(s),c=Ve?Je("billing","success","",{session_id:"{CHECKOUT_SESSION_ID}",return_to:l}):`${window.location.origin}${s}&session_id={CHECKOUT_SESSION_ID}`,u=async()=>{o(!0);try{const m=await Te.createAppStorePublishingCheckout(a.id,{success_url:c,cancel_url:window.location.href});if(m.status==="already_entitled"||!m.checkout_url){await r.invalidateQueries({queryKey:["game-settings",String(a.id)]});return}Xe("App Store Publishing Checkout Started",{game_id:a.id,amount_cents:m.amount_cents??t.price_cents}),Ze(m.checkout_url)}catch(m){et(m,i("gameSettings.appStore.checkoutFailed","Could not start checkout. Please try again.")),o(!1)}};if(t.purchased||t.is_entitled_by_allowlist)return null;const d=Pt(t.price_cents);return e.jsx("div",{"data-testid":"app-store-paywall",className:"mb-8 rounded-md border border-accent/40 bg-accent/5 p-5",children:e.jsxs("div",{className:"flex items-start gap-4 flex-wrap",children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("h3",{className:"text-sm font-medium text-foreground mb-1",children:i("gameSettings.appStore.paywallTitle","Publishing this game on the App Store costs {{price}}",{price:d})}),e.jsx("p",{className:"text-sm text-muted-foreground leading-relaxed",children:i("gameSettings.appStore.paywallBody","Fill everything in first — the form and the draft are free. The {{price}} is a one-time charge from Tesana for this game, not an Apple fee: it covers the listing, the per-device screenshots and the App Review submission. Other games are charged separately.",{price:d})})]}),e.jsxs("button",{type:"button","data-testid":"app-store-unlock",onClick:()=>void u(),disabled:p,className:"px-4 h-9 bg-accent text-accent-foreground text-sm rounded-md hover:opacity-80 transition-opacity disabled:opacity-30 cursor-pointer disabled:cursor-not-allowed font-medium shrink-0",children:[e.jsx(k,{icon:["fas","lock"],className:"mr-2 text-xs"}),p?i("gameSettings.appStore.openingCheckout","Opening checkout…"):i("gameSettings.appStore.unlock","Unlock App Store publishing — {{price}}",{price:d})]})]})})}function Rt({details:a}){const{t}=j("game"),i=a.status==="live";return e.jsxs("div",{"data-testid":"app-store-confirmed",className:"mb-8 rounded-md border border-success/30 bg-success/5 px-6 py-10 text-center",children:[e.jsx("div",{className:"animate-steam-submitted-in mx-auto mb-5 flex h-14 w-14 items-center justify-center rounded-full bg-success/15 text-success",children:e.jsx(k,{icon:["far","circle-check"],className:"text-2xl"})}),e.jsx("h3",{className:"fade-in-up stagger-1 text-2xl font-medium text-foreground",children:i?t("gameSettings.appStore.confirmed.published","Published"):t("gameSettings.appStore.confirmed.submitted","Sent to Tesana")}),e.jsx("p",{className:"fade-in-up stagger-2 mt-3 text-base text-foreground/80",children:i?t("gameSettings.appStore.confirmed.liveBody","Your game is live on the App Store — anyone can find it and play it!"):t("gameSettings.appStore.confirmed.onTheWay","You're on the way to publishing your game on the App Store!")}),e.jsx("p",{className:"fade-in-up stagger-3 mt-2 text-sm text-muted-foreground",children:t("gameSettings.appStore.confirmed.watchForUpdates","Look out for updates from the Tesana Team on your game's status!")})]})}function we({nodes:a,ariaLabel:t,testid:i}){return e.jsx("ol",{"data-testid":i,"aria-label":t,style:{gridTemplateColumns:`repeat(${a.length}, minmax(0, 1fr))`},className:"grid",children:a.map((r,p)=>{const o=r.state==="done",s=r.state==="current";return e.jsxs("li",{"data-testid":`${i}-${r.key}`,"data-state":r.state,className:"relative flex min-w-0 flex-col items-center text-center",children:[e.jsx("span",{className:_("w-7 h-7 shrink-0 rounded-full border flex items-center justify-center text-[11px] font-medium transition-colors",o&&"bg-success/15 border-success/40 text-success",s&&"bg-accent/15 border-accent/50 text-accent",!o&&!s&&"border-border text-muted-foreground"),children:o?e.jsx(k,{icon:["far","check"],className:"text-[10px]"}):p+1}),e.jsx("p",{className:_("mt-2.5 px-1 text-xs leading-snug",o?"text-foreground":s?"text-foreground font-medium":"text-muted-foreground"),children:r.label}
1),p<a.length-1&&e.jsx("span",{"aria-hidden":!0,className:_("absolute top-3.5 left-[calc(50%+17px)] right-[calc(-50%+17px)] h-px",o?"bg-success/40":"bg-border")})]},r.key)})})}function ae({built:a,access:t,details:i,settling:r,creatorStage:p="hidden",creatorStageLabel:o="",className:s}){const{t:l}=j("game"),c=!!i.initial_review_completed_at,u=!!(t?.purchased||t?.is_entitled_by_allowlist),d=le(i.status),m=[a,c,u,d],h=m.findIndex(A=>!A),f=r&&!u?2:-1,x=[{key:"built",label:l("gameSettings.appStore.flow.built","Game built"),state:"todo"},{key:"details",label:l("gameSettings.appStore.flow.details","Details filled in"),state:"todo"},{key:"payment",label:l("gameSettings.appStore.flow.payment","Publishing paid for"),state:"todo"},{key:"submit",label:l("gameSettings.appStore.flow.submit","Sent to Tesana"),state:"todo"}].map((A,g)=>{const I=m[g],L=!I&&(f===g||f<0&&h===g);return{...A,state:I?"done":L?"current":"todo"}}),v=ut(p),S=d||v>=0,N=v>=0?v:0,P=ie.map((A,g)=>({key:A.value,label:g===v&&o?o:A.label,state:g<N?"done":g===N?"current":"todo"}));return e.jsx("div",{"data-testid":"app-store-flow-root",className:s,children:S?e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"mb-3 text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:l("gameSettings.appStore.flow.afterSubmit","After you send it")}),e.jsx(we,{nodes:P,ariaLabel:l("gameSettings.appStore.creatorStageLabel","Where your submission is"),testid:"app-store-stage"}),e.jsx("p",{className:"mt-3 text-sm text-muted-foreground leading-relaxed text-center mx-auto max-w-prose",children:ie[N].blurb})]}):e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"mb-3 text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:l("gameSettings.appStore.flow.beforeSubmit","Before you send it")}),e.jsx(we,{nodes:x,ariaLabel:l("gameSettings.appStore.flow.label","Publishing progress"),testid:"app-store-flow"})]})})}const Kt=15e3,_e=1500;function qt(a,t){const i=oe(),[r]=b.useState(()=>new URLSearchParams(window.location.search).get("purchased")==="true"),[p,o]=b.useState(r&&!t),s=b.useRef(!1);return b.useEffect(()=>{const l=new URLSearchParams(window.location.search);if(l.get("purchased")!=="true")return;const c=String(a),u=l.get("session_id"),d=()=>{i.invalidateQueries({queryKey:["game-settings",c]}),i.invalidateQueries({queryKey:["app-store-details",c]}),i.invalidateQueries({queryKey:["game",a]})};l.delete("purchased"),l.delete("session_id");const m=l.toString();if(window.history.replaceState({},"",`${window.location.pathname}${m?`?${m}`:""}`),!u||s.current){d();return}s.current=!0,(async()=>{try{await Te.reconcileCheckout(u)}catch{}finally{d()}})()},[a,i]),b.useEffect(()=>{if(!r||t){o(!1);return}o(!0);let l=!1;const c=Date.now()+Kt,u=()=>{if(!l){if(i.invalidateQueries({queryKey:["game-settings",String(a)]}),Date.now()>=c){o(!1);return}d=window.setTimeout(u,_e)}};let d=window.setTimeout(u,_e);return()=>{l=!0,window.clearTimeout(d)}},[r,t,a,i]),{justPaid:r,settling:p}}function je(a,t){const i=a?.response?.data,r=i&&typeof i=="object"?Object.values(i)[0]:null,p=o=>Array.isArray(o)?typeof o[0]=="string"?o[0]:null:typeof o=="string"?o:null;return p(i?.message)||p(r)||t("gameSettings.appStore.saveFailed","Could not save. Check your connection and try again.")}function Et({error:a,timedOut:t,onRetry:i,retrying:r}){const{t:p}=j("game");return e.jsxs("div",{className:"mb-6 flex items-start gap-2.5 rounded-md border border-warning/30 bg-warning/8 px-3 py-2.5 text-xs leading-relaxed text-warning",children:[e.jsx(k,{icon:["far","circle-exclamation"],className:"text-xs mt-0.5 shrink-0"}),e.jsxs("span",{className:"min-w-0",children:[t?p("gameSettings.appStore.prefill.timedOut","This is taking longer than usual. You can answer the questions now — if the draft arrives later, it will fill in behind you."):p("gameSettings.appStore.prefill.failed","We could not draft answers from your game, so a few of these are blank. Answer what you can — nothing is blocked."),a&&e.jsx("span",{className:"block opacity-70 mt-0.5",children:a})]}),e.jsx("button",{type:"button",onClick:i,disabled:r,className:"ml-auto shrink-0 text-xs underline hover:no-underline cursor-pointer disabled:opacity-50",children:r?p("gameSettings.appStore.prefill.retrying","Trying…"):p("gameSettings.appStore.prefill.retry","Try again")})]})}function Lt({onSkip:a}){const{t}=j("game");return e.jsxs("div",{className:"rounded-md border border-border bg-card p-6","data-testid":"app-store-drafting",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(k,{icon:["far","spinner-third"],spin:!0,className:"text-muted-foreground"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:t("gameSettings.appStore.prefill.preparing","Reading your game to draft the answers")}),e.jsx("p",{className:"text-sm text-muted-foreground leading-relaxed",children:t("gameSettings.appStore.prefill.preparingBody","We are drafting what we can from the build so you can confirm it instead of starting from blank. This takes a few seconds.")})]})]}),e.jsx("button",{type:"button",onClick:a,className:"mt-5 text-xs text-muted-foreground underline hover:text-foreground hover:no-underline cursor-pointer",children:t("gameSettings.appStore.prefill.startWithout","Start without the draft")})]})}const B={app_name:"",subtitle:"",promotional_text:"",description:"",keywords:"",support_url:"",marketing_url:"",privacy_policy_url:"",copyright_line:"",developer_name:"",primary_category:"games",secondary_category:"",game_subcategory:"",is_free:!0,price_usd:null,release_option:"manual",release_date:null,phased_release:!1,pre_order:!1,available_regions:[],age_answers:[],age_rating:"4+",override_to_higher:!1,made_for_kids:!1,devices:["macos"],supported_languages:[{code:"en-US",store_listing:!0,in_game:!0}],privacy_entries:[],tracking_enabled:!1,data_deletion_url:"",export_compliance:"exempt",iap_option:"none",iap_notes:"",has_ai_generated_content:!1,ai_content_disclosure:"",content_rights_confirmed:!1,screenshot_ids:[],screenshot_notes:"",rights_confirmed:!1,third_party_ip:"",review_notes:"",demo_account_required:!1,demo_account_details:"",internal_notes:"",apple_id:"",bundle_id:"",status:"draft",creator_stage:"hidden",creator_stage_label:"",reviewer_notes:"",submitted_at:null,published_at:null,in_review_at:null,missing_requirements:[],ready_for_submission:!1,completion_percent:0,prefill_status:"idle",prefilled_at:null,prefill_error:"",ai_drafted_fields:[],initial_review_completed_at:null},ke={label:"Needs your input",blurb:"Something is missing or a claim does not match the build. What the publishing team needs is below."};function re({access:a,justPaid:t,settling:i}){const{t:r}=j("game");return t&&i?e.jsxs("div",{"data-testid":"app-store-confirmed-pending",className:"mb-8 rounded-md border border-border bg-card p-6 flex items-center gap-3",children:[e.jsx(k,{icon:["far","spinner-third"],spin:!0,className:"text-muted-foreground"}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:r("gameSettings.appStore.confirmed.settling","Confirming your payment…")}),e.jsx("p",{className:"text-sm text-muted-foreground leading-relaxed",children:r("gameSettings.appStore.confirmed.settlingBody","Your payment went through. Unlocking publishing for this game — this takes a few seconds.")})]})]}):!a?.purchased||!t?null:e.jsxs("div",{"data-testid":"app-store-paid",className:"mb-8 rounded-md border border-success/30 bg-success/5 p-6 flex items-start gap-3",children:[e.jsx(k,{icon:["far","circle-check"],className:"text-success mt-0.5"}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:r("gameSettings.appStore.confirmed.paidTitle","Payment received — publishing is unlocked")}),e.jsx("p",{className:"text-sm text-muted-foreground leading-relaxed",children:r("gameSettings.appStore.confirmed.paidBody","This game can be sent to the publishing team whenever you are ready. It is a one-time charge for this game only — your other games are separate.")})]})]})}function Ot({game:a}){const{t}=j("game"),i=oe(),[r,p]=b.useState(B),[o,s]=b.useState(!1),[l,c]=b.useState(null),[u,d]=b.useState(""),[m,h]=b.useState(!1),{data:f,isLoading:x}=st({queryKey:["app-store-details",String(a.id)],queryFn:()=>Q.getAppStoreDetails(a.id),staleTime:3e4}),{justPaid:v,settling:S}=qt(a.id,!!a.app_store_publishing?.purchased),[N,P]=b.useState(void 0);f&&f!==N&&(P(f),o||p({...B,...f}));const A=pt.has(r.status),g=b.useCallback((n,Z)=>{A||(p(Ye=>({...Ye,[n]:Z})),s(!0),c(null))},[A]),I=G({mutationFn:n=>Q.updateAppStoreDetails(a.id,n),onSuccess:n=>{p({...B,...n}),s(!1),c(Date.now()),d(""),i.invalidateQueries({queryKey:["game-settings",String(a.id)]})},onError:n=>{d(je(n,t))}}),L=G({mutationFn:()=>Q.updateAppStoreDetails(a.id,{...Ne(r),status:"ready"}),onSuccess:n=>{p({...B,...n}),s(!1),i.invalidateQueries({queryKey:["app-store-details",String(a.id)]})}}),M=a.screenshots||[],W=M.filter(n=>
1r.screenshot_ids.includes(n.id)),$=b.useCallback(async n=>{h(!0);try{const Z=await Q.uploadScreenshot(a.id,n);return i.invalidateQueries({queryKey:["game-settings",String(a.id)]}),i.invalidateQueries({queryKey:["app-store-details",String(a.id)]}),Z}catch{d(t("gameSettings.appStore.screenshotFailed","That image could not be uploaded. Try again."));return}finally{h(!1)}},[a.id,i,t]),z=b.useMemo(()=>ct(W.length,r.devices),[W.length,r.devices]),T=b.useMemo(()=>new Set(r.missing_requirements),[r.missing_requirements]),w=n=>T.has(n),E=b.useMemo(()=>new Set(r.ai_drafted_fields??[]),[r.ai_drafted_fields]),C=n=>E.has(n),{activeStep:de,goToStep:pe}=ht(),J=a.status==="completed",[Qe,Me]=b.useState(!1),[We,Be]=b.useState(!1),X=G({mutationFn:n=>Q.prefillAppStoreDetails(a.id,{force:n}),onSuccess:n=>{i.setQueryData(["app-store-details",String(a.id)],n),i.invalidateQueries({queryKey:["app-store-details",String(a.id)]})},onError:()=>{Me(!0)}}),ce=b.useRef(!1);b.useEffect(()=>{!f||ce.current||(ce.current=!0,f.prefill_status==="idle"&&X.mutate(!1))},[f]);const{awaitingDraft:$e,draftStillComing:ue,timedOut:ge}=it(r.prefill_status,{skipWait:We,dispatchFailed:Qe});b.useEffect(()=>{if(!ue)return;const n=window.setInterval(()=>{i.invalidateQueries({queryKey:["app-store-details",String(a.id)]})},2500);return()=>window.clearInterval(n)},[ue,a.id,i]);const he=G({mutationFn:n=>Q.completeAppStoreInitialReview(a.id,n),onSuccess:n=>{p({...B,...n}),s(!1),d(""),i.invalidateQueries({queryKey:["app-store-details",String(a.id)]}),i.invalidateQueries({queryKey:["game-settings",String(a.id)]})},onError:n=>{d(je(n,t))}}),ze=o&&!I.isPending,me=le(r.status),fe=!me&&r.ready_for_submission,Ge=fe&&(a.app_store_publishing?.can_prepare??!0);if(x)return e.jsxs("div",{className:"flex items-center gap-2 text-sm text-muted-foreground py-12",children:[e.jsx(k,{icon:["far","spinner-third"],spin:!0}),t("gameSettings.appStore.loading","Loading App Store details…")]});if(!r.initial_review_completed_at)return $e?e.jsxs("div",{className:xe,children:[e.jsx(ae,{built:J,access:a.app_store_publishing,details:r,settling:S,creatorStage:r.creator_stage,creatorStageLabel:r.creator_stage_label,className:"mb-8"}),e.jsx(re,{access:a.app_store_publishing,justPaid:v,settling:S}),e.jsx(Lt,{onSkip:()=>Be(!0)})]}):e.jsxs("div",{className:xe,children:[e.jsx(ae,{built:J,access:a.app_store_publishing,details:r,settling:S,creatorStage:r.creator_stage,creatorStageLabel:r.creator_stage_label,className:"mb-8"}),e.jsx(re,{access:a.app_store_publishing,justPaid:v,settling:S}),(r.prefill_status==="failed"||ge)&&e.jsx(Et,{error:r.prefill_status==="failed"?r.prefill_error:"",timedOut:ge&&r.prefill_status!=="failed",onRetry:()=>X.mutate(!0),retrying:X.isPending}),e.jsx(_t,{details:r,screenshots:M,onScreenshotUpload:$,uploadingScreenshot:m,onSubmit:n=>he.mutateAsync(n),submitting:he.isPending,error:u})]});const be=Oe(r.devices);return e.jsxs("div",{className:"pb-12",children:[a.app_store_publishing&&!a.app_store_publishing.can_prepare&&!S&&e.jsx(Ct,{game:a,access:a.app_store_publishing}),me&&e.jsx(Rt,{details:r}),e.jsx(re,{access:a.app_store_publishing,justPaid:v,settling:S}),e.jsxs("div",{className:"mb-8 bg-card rounded-md border border-border p-6",children:[e.jsx(ae,{built:J,access:a.app_store_publishing,details:r,settling:S,creatorStage:r.creator_stage,creatorStageLabel:r.creator_stage_label,className:"mb-4"}),r.bundle_id&&e.jsxs("p",{className:"text-[11px] text-muted-foreground/70 text-center",children:[t("gameSettings.appStore.bundleId","Bundle ID"),":"," ",e.jsx("span",{className:"font-mono",children:r.bundle_id})]})]}),r.reviewer_notes&&e.jsxs("div",{className:"mb-8 rounded-md border border-warning/30 bg-warning/8 p-4",children:[e.jsxs("p",{className:"text-sm font-medium text-foreground mb-1 flex items-center gap-2",children:[e.jsx(k,{icon:["far","circle-exclamation"],className:"text-warning text-xs"}),r.status==="blocked"?t("gameSettings.appStore.blockedLabel",ke.label):t("gameSettings.appStore.notesFromTesana","Notes from the publishing team")]}),r.status==="blocked"&&e.jsx("p",{className:"text-sm text-muted-foreground mb-2 leading-relaxed",children:t("gameSettings.appStore.blockedBlurb",ke.blurb)}),e.jsx("p",{className:"text-sm text-muted-foreground whitespace-pre-wrap leading-relaxed",children:r.reviewer_notes})]}),e.jsx(ye,{variant:"list",activeStep:de,onSelect:pe}),e.jsxs("div",{className:"flex gap-10 items-start",children:[e.jsx(ye,{variant:"rail",activeStep:de,onSelect:pe}),e.jsx(ot.Provider,{value:A,children:e.jsxs("div",{className:_("min-w-0 flex-1",A&&"steam-locked"),children:[e.jsxs(D,{step:1,description:t("gameSettings.appStore.step1.desc","What players read on the product page. Apple caps the name and subtitle at 30 characters each, and counts every keyword against a single 100-character budget."),children:[e.jsx(y,{label:t("gameSettings.appStore.nameLabel","App name"),required:!0,missing:w("app_name"),drafted:C("app_name"),hint:t("gameSettings.appStore.nameHint","The name shown under the icon in search and on the product page. Apple does not allow it to be changed while a ver
1sion is in review."),children:e.jsx(K,{value:r.app_name,onChange:n=>g("app_name",n),maxLength:30,placeholder:a.name})}),e.jsx(y,{label:t("gameSettings.appStore.subtitleLabel","Subtitle"),required:!0,missing:w("subtitle"),drafted:C("subtitle"),hint:t("gameSettings.appStore.subtitleHint","One line under the name, at most 30 characters. It appears in search results, so it should say what the game is rather than repeat the name."),children:e.jsx(R,{value:r.subtitle,onChange:n=>g("subtitle",n),rows:1,autoGrow:!0,maxLength:30,showCount:!0})}),e.jsx(y,{label:t("gameSettings.appStore.descriptionLabel","Description"),required:!0,missing:w("description"),drafted:C("description"),hint:t("gameSettings.appStore.descriptionHint","The body of the product page. Apple rejects a description that links to another store, prices the game outside the app, or promises a feature the build does not have."),children:e.jsx(R,{value:r.description,onChange:n=>g("description",n),rows:8,placeholder:t("gameSettings.appStore.descriptionPlaceholder","What the player does, and why it is fun…")})}),e.jsx(y,{label:t("gameSettings.appStore.keywordsLabel","Keywords"),required:!0,missing:w("keywords"),drafted:C("keywords"),hint:t("gameSettings.appStore.keywordsHint","Comma-separated, at most 100 characters in total. Apple already indexes the app name, so repeating it here wastes the budget."),children:e.jsx(K,{value:r.keywords,onChange:n=>g("keywords",n),maxLength:100,placeholder:t("gameSettings.appStore.keywordsPlaceholder","neon, arcade, chase, retro")})}),e.jsxs("div",{className:"grid sm:grid-cols-2 gap-4",children:[e.jsx(y,{label:t("gameSettings.appStore.categoryLabel","Primary category"),required:!0,missing:w("primary_category"),children:e.jsx(ee,{value:r.primary_category,onChange:n=>g("primary_category",n),options:se})}),e.jsx(y,{label:t("gameSettings.appStore.secondaryCategory","Secondary category"),hint:t("gameSettings.appStore.secondaryCategoryHint","Optional, and it cannot be the same as the primary. A second category puts the game in a second set of charts."),children:e.jsx(ee,{value:r.secondary_category,onChange:n=>g("secondary_category",n),options:[{value:"",label:t("gameSettings.appStore.none","None")},...se.filter(n=>n.value!==r.primary_category)]})})]}),r.primary_category==="games"&&e.jsx(y,{label:t("gameSettings.appStore.subcategoryLabel","Game subcategory"),required:!0,missing:w("game_subcategory"),children:e.jsx(ee,{value:r.game_subcategory,onChange:n=>g("game_subcategory",n),options:[{value:"",label:t("gameSettings.appStore.choose","Choose…")},...Ce]})}),e.jsx(y,{label:t("gameSettings.appStore.developerLabel","Developer name"),drafted:C("developer_name"),hint:t("gameSettings.appStore.developerHint","Shown as the seller on the product page. This is the name Apple files the listing under, so it is usually your own name or your studio’s."),children:e.jsx(K,{value:r.developer_name,onChange:n=>g("developer_name",n),maxLength:255,placeholder:t("gameSettings.appStore.developerPlaceholder","Your studio or your name")})}),e.jsxs("div",{className:"grid sm:grid-cols-2 gap-4",children:[e.jsx(y,{label:t("gameSettings.appStore.supportUrlLabel","Support URL"),required:!0,missing:w("support_url"),hint:t("gameSettings.appStore.supportUrlHint","Apple checks that this loads and that it says how to reach you. A dead link is a rejection."),children:e.jsx(K,{type:"url",value:r.support_url,onChange:n=>g("support_url",n),placeholder:"https://"})}),e.jsx(y,{label:t("gameSettings.appStore.privacyUrlLabel","Privacy policy URL"),required:!0,missing:w("privacy_policy_url"),hint:t("gameSettings.appStore.privacyUrlHint","Required for every app. Apple checks that it loads and that it covers the data your privacy label declares."),children:e.jsx(K,{type:"url",value:r.privacy_policy_url,onChange:n=>g("privacy_policy_url",n),placeholder:"https://"})})]}),e.jsxs("div",{className:"grid sm:grid-cols-2 gap-4",children:[e.jsx(y,{label:t("gameSettings.appStore.marketingUrlLabel","Marketing URL"),hint:t("gameSettings.appStore.marketingUrlHint","Optional. A trailer or a landing page."),children:e.jsx(K,{type:"url",value:r.marketing_url,onChange:n=>g("marketing_url",n),placeholder:"https://"})}),e.jsx(y,{label:t("gameSettings.appStore.copyrightLabel","Copyright line"),required:!0,missing:w("copyright_line"),hint:t("gameSettings.appStore.copyrightHint","The line printed in the footer of the product page, usually the year and the rights holder."),children:e.jsx(K,{value:r.copyright_line,onChange:n=>g("copyright_line",n),maxLength:200,placeholder:t("gameSettings.appStore.copyrightPlaceholder","2026 Your Name")}
1)})]}),e.jsx(y,{label:t("gameSettings.appStore.promoTextLabel","Promotional text"),drafted:C("promotional_text"),hint:t("gameSettings.appStore.promoTextHint","Up to 170 characters, shown above the description. Unlike the description this can be changed at any time without a new review, so it is the place for news."),children:e.jsx(R,{value:r.promotional_text,onChange:n=>g("promotional_text",n),rows:3,maxLength:170,showCount:!0})})]}),e.jsxs(D,{step:2,description:t("gameSettings.appStore.step2.desc",'Whether the game is free, and what happens the moment Apple approves it. There is no wishlist or "coming soon" state on the App Store, so the release decision is made here rather than later.'),children:[e.jsx(O,{label:t("gameSettings.appStore.freeLabel","Free to download"),sublabel:t("gameSettings.appStore.freeHint","A free game can still sell coins inside it. Turning this off adds a price below."),enabled:r.is_free,onToggle:n=>g("is_free",n)}),w("is_free")&&e.jsx("p",{className:"text-[11px] text-warning mb-4 -mt-2",children:t("gameSettings.appStore.freeOutstanding","Tell Apple whether this game is free.")}),!r.is_free&&e.jsx(y,{label:t("gameSettings.appStore.priceLabel","Price (USD)"),required:!0,missing:w("price_usd"),hint:t("gameSettings.appStore.priceHint","Apple converts this into every other region and picks the nearest of its own price tiers, so this is the only price you set."),children:e.jsx(K,{type:"number",value:r.price_usd??"",onChange:n=>g("price_usd",n===""?null:n),mono:!0,placeholder:"4.99"})}),e.jsx(y,{label:t("gameSettings.appStore.releaseOptionLabel","Release timing"),required:!0,missing:w("release_option"),children:e.jsx(te,{options:Ie.map(n=>({value:n.value,labelKey:n.labelKey,label:n.label,hint:n.hint})),value:r.release_option,onChange:n=>g("release_option",n)})}),r.release_option==="scheduled"&&e.jsx(y,{label:t("gameSettings.appStore.releaseDateLabel","Release date"),required:!0,missing:w("release_date"),hint:t("gameSettings.appStore.releaseDateHint","Apple will not hold a scheduled listing longer than two days past this without putting it through another review."),children:e.jsx(K,{type:"date",value:r.release_date??"",onChange:n=>g("release_date",n===""?null:n)})}),e.jsxs("div",{className:"mt-4",children:[e.jsx(O,{label:t("gameSettings.appStore.phasedLabel","Phased release"),sublabel:t("gameSettings.appStore.phasedHint","Apple rolls the update out to a rising percentage of players over seven days. Useful for a live game with an update, no use for a first release."),enabled:r.phased_release,onToggle:n=>g("phased_release",n)}),e.jsx(O,{label:t("gameSettings.appStore.preOrderLabel","Offer for pre-order"),sublabel:t("gameSettings.appStore.preOrderHint","Players can reserve the game before release and it downloads automatically on the day. Needs a release date two to 180 days out."),enabled:r.pre_order,onToggle:n=>g("pre_order",n),disabled:r.release_option!=="scheduled"})]})]}),e.jsxs(D,{step:3,description:t("gameSettings.appStore.step3.desc",'Apple works the rating out from this questionnaire rather than letting you pick one, and shows it on the product page. Every question needs an answer — Apple cannot tell an unanswered one from a "no".'),children:[e.jsx(Ht,{value:r.age_answers,onChange:n=>g("age_answers",n),readOnly:A}),e.jsxs("div",{className:"mt-6",children:[e.jsx(y,{label:t("gameSettings.appStore.derivedRating","Rating Apple will assign"),hint:t("gameSettings.appStore.derivedRatingHint","Derived from the answers above. It is shown here so you can see what players will see before you submit."),children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"px-3 h-9 inline-flex items-center rounded-md border border-border text-sm text-foreground",children:r.age_rating||"4+"}),e.jsx(O,{label:t("gameSettings.appStore.overrideRating","Ask for a higher rating"),enabled:r.override_to_higher,onToggle:n=>g("override_to_higher",n)})]})}),e.jsx(O,{label:t("gameSettings.appStore.madeForKids","Made for Kids"),sublabel:t("gameSettings.appStore.madeForKidsHint","Only for apps designed for children under 13. It is a different, stricter review — and a game with a shop or a chat is not eligible."),enabled:r.made_for_kids,onToggle:n=>g("made_for_kids",n)})]})]}),e.jsxs(D,{step:4,description:t("gameSettings.appStore.step4.desc","The device list decides which screenshot sizes Apple requires and which builds we maintain. The language list is what the listing is translated into."),children:[e.jsx(y,{label:t("gameSettings.appStore.devicesLabel","Devices"),required:!0,missing:w("devices"),drafted:C("devices"),hint:t("gameSettings.appStore.devicesHint","Mac is the desktop build the export already produces. iPhone, iPad, Apple TV and Vision Pro each need their own layout and testing."),children:e.jsx(lt,{options:Ee,value:r.devices,onChange:n=>g("devices",n)})}),be.length>0&&e.jsx(H,{children:t("gameSettings.appStore.devicesScreenshots","This device list needs screenshots at: {{sizes}}. Apple will not accept the listing without them.",{sizes:be.map(n=>`${n.name} (${n.size})`).join(", ")})}),e.jsx(y,{label:t("gameSettings.appStore.languagesLabel","Languages"),required:!0,missing:w("supported_languages"),hint:t("gameSettings.appStore.languagesHint","English is required. Add anything else the listing is translated into — claiming a language the game does not have produces poor reviews."),children:e.jsx(Dt,{value:r.supported_languages,onChange:n=>g("supported_languages",n)})})]}),e.jsxs(D,{step:5,description:t("gameSettings.appStore.step5.desc","The privacy label players read before installing, plus Apple’s export and in-app-purchase questions. This is the half of the form Apple holds you to, so it is the one to read twice."),children:[e.jsx(y,{label:t("gameSettings.appStore.privacyLabel","Privacy label"),required:!0,missing:w("privacy_entries"),hint:t("gameSettings.appStore.privacyHint","Every data type needs an answer. A Tesana game with saves is collecting the account id and the gameplay content — check the ones that apply."),children:e.jsx(It,{value:r.privacy_entries,onChange:n=>g("privacy_entries",n)})}),e.jsx(O,{label:t("gameSettings.appStore.trackingLabel","Tracks players across other apps"),sublabel:t("gameSettings.appStore.trackingHint","Almost always no. Turning this on requires Apple’s permission prompt before anything is tracked, and refusing it must not degrade the game."),enabled:r.tracking_enabled,onToggle:n=>g("tracking_enabled",n)}),e.jsx(y,{label:t("gameSettings.appStore.deletionLabel","Data deletion URL"),hint:t("gameSettings.appStore.deletionHint","Where a player asks for their data to be deleted. Apple requires this once the app has an account, which a game with saves does."),children:e.jsx(K,{type:"url",value:r.data_deletion_url,onChange:n=>g("data_deletion_url",n),placeholder:"https://"})}),e.jsx(y,{label:t("gameSettings.appStore.exportLabel","Export compliance"),required:!0,missing:w("export_
1compliance"),hint:t("gameSettings.appStore.exportHint",'Apple asks every submission about encryption, even a game that makes no network calls. "Only exempt encryption" is the answer for nearly every Tesana game.'),children:e.jsx(te,{options:Ke.map(n=>({value:n.value,label:n.label,hint:n.hint})),value:r.export_compliance,onChange:n=>g("export_compliance",n)})}),e.jsx(y,{label:t("gameSettings.appStore.iapLabel","In-app purchases"),required:!0,missing:w("iap_option"),hint:t("gameSettings.appStore.iapHint","This is the answer that changes what the listing is. Apple requires digital goods sold inside an app to go through In-App Purchase, at Apple’s commission — so a coin shop cannot keep using Stripe on iOS."),children:e.jsx(te,{options:qe.map(n=>({value:n.value,label:n.label,hint:n.hint})),value:r.iap_option,onChange:n=>g("iap_option",n)})}),r.iap_option==="coins_only"&&e.jsx(y,{label:t("gameSettings.appStore.iapNotesLabel","What the game sells"),required:!0,missing:w("iap_notes"),hint:t("gameSettings.appStore.iapNotesHint","What the coins buy, and whether anything is consumable. This goes to Apple’s reviewer and to the publishing team, who need it to plan the StoreKit work."),children:e.jsx(R,{value:r.iap_notes,onChange:n=>g("iap_notes",n),rows:3})}),e.jsx(O,{label:t("gameSettings.appStore.aiContentLabel","Contains AI-generated content"),sublabel:t("gameSettings.appStore.aiContentHint","Apple asks this on every submission. Tesana builds these games with generated art, audio and code, so it is usually yes."),enabled:r.has_ai_generated_content,onToggle:n=>g("has_ai_generated_content",n)}),r.has_ai_generated_content&&e.jsx(y,{label:t("gameSettings.appStore.aiDisclosureLabel","AI content disclosure"),required:!0,missing:w("ai_content_disclosure"),drafted:C("ai_content_disclosure"),hint:t("gameSettings.appStore.aiDisclosureHint","Goes to App Review verbatim. Say which art, audio or text was generated and whether it was made ahead of time or while the game runs."),children:e.jsx(R,{value:r.ai_content_disclosure,onChange:n=>g("ai_content_disclosure",n),rows:5,placeholder:Pe})}),e.jsx(O,{label:t("gameSettings.appStore.contentRightsLabel","No third-party content is used without permission"),sublabel:t("gameSettings.appStore.contentRightsHint","Covers music, art, fonts, names and any third-party code. Apple rejects an app it cannot see the rights to."),enabled:r.content_rights_confirmed,onToggle:n=>g("content_rights_confirmed",n)}),w("content_rights_confirmed")&&e.jsx("p",{className:"text-[11px] text-warning mb-4 -mt-2",children:t("gameSettings.appStore.contentRightsOutstanding","Not confirmed yet — Apple will not accept a listing without it.")})]}),e.jsxs(D,{step:6,description:t("gameSettings.appStore.step6.desc","Apple builds the per-device sizes from the pictures you choose, and shows the first two in search results. At least three are required."),children:[e.jsx(y,{label:t("gameSettings.appStore.shotsLabel","Pictures for the product page"),required:!0,missing:w("screenshot_ids"),hint:t("gameSettings.appStore.shotsHint","In this order. Lead with the one that explains the game fastest — that is what Apple shows in search."),children:e.jsx(Ut,{screenshots:M,selected:r.screenshot_ids,onChange:n=>g("screenshot_ids",n),onUpload:$,uploading:m})}),z&&e.jsx(H,{tone:"warn",children:z}),e.jsxs("details",{className:"mb-5",children:[e.jsx("summary",{className:"text-xs text-muted-foreground cursor-pointer hover:text-foreground",children:t("gameSettings.appStore.shotSpecs","The sizes Apple requires for this device list")}),e.jsx("ul",{className:"mt-3 space-y-1.5",children:Le.filter(n=>r.devices.includes(n.forDevice)).map(n=>e.jsxs("li",{className:"text-[11px] text-muted-foreground flex gap-2",children:[e.jsx("span",{className:"text-foreground w-28 shrink-0",children:n.name}),e.jsx("span",{className:"font-mono shrink-0",children:n.size}),e.jsx("span",{className:"min-w-0",children:n.note})]},n.name))})]}),e.jsx(y,{label:t("gameSettings.appStore.shotNotesLabel","Notes about the pictures"),hint:t("gameSettings.appStore.shotNotesHint","Anything the publishing team should know — which device each picture came from, or one that needs cropping."),children:e.jsx(R,{value:r.screenshot_notes,onChange:n=>g("screenshot_notes",n),rows:3})})]}),e.jsxs(D,{step:7,description:t("gameSettings.appStore.step7.desc","The affirmations, and a place to tell App Review and the publishing team anything the form cannot capture."),children:[e.jsx(O,{label:t("gameSettings.appStore.rightsLabel","I own or have licensed everything in this game"),sublabel:t("gameSettings.appStore.rightsHint","Required. Covers art, audio, fonts, names and any third-party code. This is what Apple holds us to, so it has to be true."),enabled:r.rights_confirmed,onToggle:n=>
1g("rights_confirmed",n)}),w("rights_confirmed")&&e.jsx("p",{className:"text-[11px] text-warning mb-4 -mt-2",children:t("gameSettings.appStore.rightsOutstanding","Not confirmed yet — this is the last required box.")}),e.jsx(y,{label:t("gameSettings.appStore.thirdPartyLabel","Third-party content"),hint:t("gameSettings.appStore.thirdPartyHint","Licensed engines, middleware, fonts and music, with their licence terms."),children:e.jsx(R,{value:r.third_party_ip,onChange:n=>g("third_party_ip",n),rows:3,placeholder:t("gameSettings.appStore.thirdPartyPlaceholder","e.g. Three.js (MIT), Rapier (Apache-2.0), music licensed from…")})}),e.jsx(O,{label:t("gameSettings.appStore.demoRequiredLabel","App Review needs an account to try the game"),sublabel:t("gameSettings.appStore.demoRequiredHint","A Tesana game plays without signing in, so this is usually off. If it is on, Apple needs working credentials below or the submission is rejected."),enabled:r.demo_account_required,onToggle:n=>g("demo_account_required",n)}),r.demo_account_required&&e.jsx(y,{label:t("gameSettings.appStore.demoDetailsLabel","Sign-in for the reviewer"),required:!0,missing:w("demo_account_details"),hint:t("gameSettings.appStore.demoDetailsHint","A working username and password, and any step needed to reach the part of the game you want reviewed. These go to App Review and are never public."),children:e.jsx(R,{value:r.demo_account_details,onChange:n=>g("demo_account_details",n),rows:3})}),e.jsx(y,{label:t("gameSettings.appStore.reviewNotesLabel","Notes for App Review"),drafted:C("review_notes"),hint:t("gameSettings.appStore.reviewNotesHint","Tell Apple’s reviewer about anything non-obvious — an unusual control, a feature that looks like something it is not. A reviewer who cannot find a feature rejects the app rather than asking."),children:e.jsx(R,{value:r.review_notes,onChange:n=>g("review_notes",n),rows:4})}),e.jsx(y,{label:t("gameSettings.appStore.internalNotesLabel","Notes for the publishing team"),hint:t("gameSettings.appStore.internalNotesHint","Anything the form does not cover — timing, embargoes, a heads-up about a tricky disclosure. Never shown on the store page."),children:e.jsx(R,{value:r.internal_notes,onChange:n=>g("internal_notes",n),rows:3})})]})]})})]}),e.jsx("div",{className:"sticky bottom-0 -mx-4 md:-mx-8 px-4 md:px-8 py-3 bg-background/95 border-t border-border z-10",children:e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[A?e.jsxs("span",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:[e.jsx(k,{icon:["far","lock"],className:"text-[11px]"}),t("gameSettings.appStore.readOnly","You have handed this submission in, so the details are locked. The publishing team will pick it up from here — contact us if something needs to change.")]},"readonly"):e.jsx("button",{type:"button","data-testid":"app-store-save",onClick:()=>I.mutate(Ne(r)),disabled:!ze,className:"px-4 h-9 bg-foreground text-background text-sm rounded-md hover:opacity-80 transition-opacity disabled:opacity-30 cursor-pointer disabled:cursor-not-allowed font-medium",children:I.isPending?t("gameSettings.saving","Saving…"):t("gameSettings.save","Save")},"save"),Ge?e.jsx("button",{type:"button",onClick:()=>L.mutate(),disabled:L.isPending||o,title:o?t("gameSettings.appStore.saveFirst","Save your changes first"):void 0,className:"px-4 h-9 bg-accent text-accent-foreground text-sm rounded-md hover:opacity-80 transition-opacity disabled:opacity-30 cursor-pointer disabled:cursor-not-allowed font-medium",children:L.isPending?t("gameSettings.appStore.sending","Sending…"):t("gameSettings.appStore.markReady","Send to Tesana")}):fe&&e.jsx("span",{className:"text-xs text-muted-foreground",children:t("gameSettings.appStore.paywallBeforeReady","Unlock App Store publishing above to send this to Tesana.")}),e.jsx("span",{className:"text-xs text-muted-foreground",children:u?e.jsx("span",{className:"text-destructive",children:u}):l?e.jsxs("span",{className:"text-success flex items-center gap-1.5",children:[e.jsx(k,{icon:["far","circle-check"],className:"text-[10px]"}),t("gameSettings.saved","Saved!")]}):o?t("gameSettings.appStore.unsaved","Unsaved changes"):t("gameSettings.appStore.allSaved","Everything is saved.")}),!r.ready_for_submission&&e.jsx("span",{className:"text-xs text-muted-foreground ml-auto",children:t("gameSettings.appStore.stillNeeded","{{count}} item(s) still needed",{count:r.missing_requirements.length})})]})})]})}function Ne(a){const{apple_id:t,bundle_id:i,status:r,reviewer_notes:p,submitted_at:o,published_at:s,in_review_at:l,missing_requirements:c,ready_for_submission:u,completion_percent:d,creator_stage:m,creator_stage_label:h,prefill_status:f,prefilled_at:x,prefill_error:v,ai_drafted_fields:S,initial_review_completed_at:N,...P}=a;return P}function Ht({value:a,onChange:t,readOnly:i}
1){const{t:r}=j("game"),p=V(U,s=>s.group,s=>s.value),o=b.useMemo(()=>{const s=new Map(a.map(l=>[l.topic,l.frequency]));return U.map(l=>({topic:l.value,frequency:s.get(l.value)??"none"}))},[a]);return e.jsx("div",{className:"space-y-5",children:p.map(s=>e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] uppercase tracking-wide text-muted-foreground/60 mb-2",children:s.group}),e.jsx("div",{className:"space-y-2",children:s.values.map(l=>{const c=U.find(d=>d.value===l),u=o.find(d=>d.topic===l);return e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs("span",{className:"text-sm text-foreground min-w-0 flex-1",children:[c.label,c.hint&&e.jsx("span",{className:"block text-[11px] text-muted-foreground mt-0.5",children:c.hint})]}),e.jsx("div",{className:"flex gap-1 shrink-0",children:Re.map(d=>e.jsx("button",{type:"button","aria-pressed":u.frequency===d,disabled:i,onClick:()=>t(o.map(m=>m.topic===l?{...m,frequency:d}:m)),className:_("px-2.5 py-1 rounded-md text-[11px] border transition-colors capitalize",u.frequency===d?"border-accent/40 bg-accent/15 text-accent":"border-border bg-foreground
1/3 text-muted-foreground hover:text-foreground",i?"cursor-default":"cursor-pointer"),children:r(`gameSettings.appStore.frequency.${d}`,d)},d))})]},l)})})]},s.group))})}function It({value:a,onChange:t}){const{t:i}=j("game"),r=V(F,s=>s.group,s=>s.value),p=b.useMemo(()=>{const s=new Map(a.map(l=>[l.type,l]));return F.map(l=>s.get(l.value)??{type:l.value,collected:!1,linked_to_identity:!1,used_for_tracking:!1,purposes:[]})},[a]),o=(s,l)=>t(p.map(c=>c.type===s?{...c,...l}:c));return e.jsx("div",{className:"space-y-5",children:r.map(s=>e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] uppercase tracking-wide text-muted-foreground/60 mb-2",children:s.group}),e.jsx("div",{className:"space-y-2",children:s.values.map(l=>{const c=F.find(d=>d.value===l),u=p.find(d=>d.type===l);return e.jsxs("div",{className:"rounded-md border border-border p-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs("span",{className:"text-sm text-foreground min-w-0 flex-1",children:[c.label,c.hint&&e.jsx("span",{className:"block text-[11px] text-muted-foreground mt-0.5",children:c.hint})]}),e.jsx("div",{className:"flex gap-1 shrink-0",children:[{on:!1,labelKey:"gameSettings.appStore.review.notCollected",label:"Not collected"},{on:!0,labelKey:"gameSettings.appStore.review.collected",label:"Collected"}].map(d=>e.jsx("button",{type:"button","aria-pressed":u.collected===d.on,onClick:()=>o(l,d.on?{collected:!0}:{collected:!1,linked_to_identity:!1,used_for_tracking:!1,purposes:[]}),className:_("px-2.5 py-1 rounded-md text-[11px] border transition-colors cursor-pointer",u.collected===d.on?"border-accent/40 bg-accent/15 text-accent":"border-border bg-foreground
1/3 text-muted-foreground hover:text-foreground"),children:i(d.labelKey,d.label)},String(d.on)))})]}),u.collected&&e.jsxs("div",{className:"mt-3 pl-3 border-l border-border space-y-3",children:[e.jsx(Ae,{label:i("gameSettings.appStore.linkedQuestion","Linked to the player’s identity"),value:u.linked_to_identity,onChange:d=>o(l,{linked_to_identity:d})}),e.jsx(Ae,{label:i("gameSettings.appStore.trackingDataQuestion","Used for tracking"),value:u.used_for_tracking,onChange:d=>o(l,{used_for_tracking:d})}),e.jsxs("div",{children:[e.jsx("p",{className:"text-xs text-muted-foreground mb-2",children:i("gameSettings.appStore.purposesQuestion","Why it is collected (pick at least one)")}),e.jsx("div",{className:"flex flex-wrap gap-1.5",children:He.map(d=>{const m=u.purposes.includes(d.value);return e.jsx("button",{type:"button","aria-pressed":m,onClick:()=>o(l,{purposes:m?u.purposes.filter(h=>h!==d.value):[...u.purposes,d.value]}),className:_("px-2.5 py-1 rounded-md text-[11px] border transition-colors cursor-pointer",m?"border-accent/40 bg-accent/15 text-accent":"border-border bg-foreground
1/3 text-muted-foreground hover:text-foreground"),children:i(`gameSettings.appStore.privacyPurpose.${d.value}`,d.label)},d.value)})})]})]})]},l)})})]},s.group))})}function Ae({label:a,value:t,onChange:i}){const{t:r}=j("game");return e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("span",{className:"text-xs text-muted-foreground min-w-0 flex-1",children:a}),e.jsx("div",{className:"flex gap-1 shrink-0",children:[!0,!1].map(p=>e.jsx("button",{type:"button","aria-pressed":t===p,onClick:()=>i(p),className:_("px-2.5 py-1 rounded-md text-[11px] border transition-colors cursor-pointer",t===p?"border-accent/40 bg-accent/15 text-accent":"border-border bg-foreground/3 text-muted-foreground hover:text-foreground"),children:p?r("gameSettings.appStore.review.yes","Yes"):r("gameSettings.appStore.review.no","No")},String(p)))})]})}function Dt({value:a,onChange:t}){const{t:i}=j("game"),r=o=>a.find(s=>s.code===o)??{code:o,store_listing:!1,in_game:!1},p=(o,s)=>{if(!a.find(u=>u.code===o)){t([...a,{code:o,store_listing:!1,in_game:!1,...s}]);return}const c=a.map(u=>u.code===o?{...u,...s}:u);t(c.filter(u=>u.store_listing||u.in_game))};return e.jsx("div",{className:"space-y-1.5",children:De.map(o=>{const s=r(o.code),l=s.store_listing||s.in_game;return e.jsxs("div",{className:_("flex flex-wrap items-center gap-3 rounded-md border px-3 py-2.5 transition-colors",l?"border-accent/40 bg-accent/5":"border-border bg-foreground
1/3"),children:[e.jsxs("span",{className:_("text-sm min-w-0 flex-1",l?"text-foreground":"text-muted-foreground"),children:[o.label,e.jsx("span",{className:"ml-2 font-mono text-[11px] text-muted-foreground/60",children:o.code})]}),[{key:"store_listing",label:i("gameSettings.appStore.langListing","On the store page")},{key:"in_game",label:i("gameSettings.appStore.langInGame","Playable in game")}].map(c=>e.jsx("button",{type:"button","aria-pressed":s[c.key],onClick:()=>p(o.code,{[c.key]:!s[c.key]}),className:_("px-2.5 py-1 rounded-md text-[11px] border transition-colors cursor-pointer",s[c.key]?"border-accent/40 bg-accent/15 text-accent":"border-border bg-foreground/3 text-muted-foreground hover:text-foreground"),children:c.label},c.key))]},o.code)})})}function Ut({screenshots:a,selected:t,onChange:i,onUpload:r,uploading:p}){const{t:o}=j("game"),s=b.useRef(null),[l,c]=b.useState(""),u=Math.max(0,q.minimum-t.length),d=a.length>=6,m=f=>{const x=f.target.files?.[0];if(s.current&&(s.current.value=""),!!x){if(!x.type.startsWith("image/")){c(o("gameSettings.screenshots.selectImage","Please select an image file."));return}if(x.size>5*1024*1024){c(o("gameSettings.screenshots.imageTooLarge","Image must be under 5MB."));return}c(""),r(x).then(v=>{v&&i([...t,v.id])})}},h=f=>i(t.includes(f)?t.filter(x=>x!==f):[...t,f]);return e.jsxs("div",{children:[e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-3 gap-2",children:[e.jsx("button",{type:"button",onClick:()=>s.current?.click(),disabled:p||d,className:_("flex flex-col items-center justify-center gap-1 aspect-video rounded-md border border-dashed border-border transition-colors cursor-pointer","text-muted-foreground hover:text-foreground hover:border-foreground
1/30","disabled:opacity-40 disabled:cursor-not-allowed"),children:p?e.jsxs(e.Fragment,{children:[e.jsx(k,{icon:["far","spinner"],spin:!0,className:"text-base"}),e.jsx("span",{className:"text-[10px]",children:o("gameSettings.screenshots.uploading","Uploading…")})]}):e.jsxs(e.Fragment,{children:[e.jsx(k,{icon:["far","plus"],className:"text-base"}),e.jsx("span",{className:"text-[10px]",children:d?o("gameSettings.screenshots.limitReached","Maximum 6 screenshots"):o("gameSettings.appStore.shotsAdd","Add a screenshot")})]})}),a.map(f=>{const x=t.includes(f.id);return e.jsxs("button",{type:"button","aria-pressed":x,onClick:()=>h(f.id),className:_("relative aspect-video rounded-md overflow-hidden border-2 transition-all cursor-pointer",x?"border-accent":"border-transparent opacity-60 hover:opacity-100"),children:[e.jsx("img",{src:f.image,alt:f.caption||"",className:"w-full h-full object-cover"}),x&&e.jsx("span",{className:"absolute top-1 right-1 w-5 h-5 rounded-full bg-accent text-accent-foreground flex items-center justify-center",children:e.jsx(k,{icon:["far","check"],className:"text-[10px]"})})]},f.id)})]}),e.jsx("input",{ref:s,type:"file",accept:"image/*",onChange:m,className:"hidden"}),l&&e.jsx("p",{className:"text-[11px] text-destructive mt-2",children:l}),u>0&&e.jsx("div",{className:"mt-3",children:e.jsx(H,{tone:"warn",children:o("gameSettings.appStore.shotsMore","Apple needs at least {{count}} — choose {{missing}} more.",{count:q.minimum,missing:u})})})]})}function Gt(){const{game:a}=at(),{user:t}=tt();return a.organization||!t?.can_publish_to_appstore||a.app_store_publishing?.can_view===!1?e.jsx(rt,{to:`/studio/${a.id}/settings/information`,replace:!0}):e.jsx(e.Fragment,{children:e.jsx(Ot,{game:a})})}export{Gt as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.