diff --git a/docs/sdks/ios/sparkscan/intro.md b/docs/sdks/ios/sparkscan/intro.md index 0c4784a07f..da671845b4 100644 --- a/docs/sdks/ios/sparkscan/intro.md +++ b/docs/sdks/ios/sparkscan/intro.md @@ -5,12 +5,69 @@ sidebar_position: 1 displayed_sidebar: iosSidebar pagination_prev: null framework: ios +product: sparkscan +user_intents: + - "scan one barcode at a time on iOS" + - "add a ready-made scanning UI without building your own" + - "scan items one by one to build a list (inventory, receiving)" +not_for: + - "scan and count many barcodes at once — use MatrixScan Count" + - "build a fully custom scanning UI — use Barcode Capture" keywords: - ios --- +import ProductChooser from '@site/src/components/ProductChooser'; + # About SparkScan import AboutSparkScan from '../../../partials/intro/_about-sparkscan.mdx'; +SparkScan bundles multiple scanning features together and addresses many common challenges associated with scanning on smart devices. It is designed to be easily integrated into any application, and can be customized to fit your specific needs. + + + +## UI Overview + +The UI elements in SparkScan are intentionally minimalistic, meant to be overlayed on any application without the need to adapt the existing app while offering the best user experience. + +Two main elements compose the UI: + +![SparkScan UI](/img/sparkscan/features_web.png) + +- **Camera preview**: A small camera preview that helps with aiming and shows scan feedback. When not in use, the camera preview is hidden. It can be expanded and hosts easy to access controls (zoom level, flash etc). +- **Trigger button**: A large-sized, semi-transparent floating button that users can drag to position it in the most ergonomic position. When not in use, the trigger button collapses to occupy less space. + +There are additional UI elements available for displaying additional scanning modes, errors, or providing feedback to the user. These are described in the [Advanced](./advanced.md) section. + +## Workflow Description + +When SparkScan is started, the UI presents just the trigger button, collapsed. The user can move the trigger button by simply dragging it around: the position of the trigger button is remembered across sessions, so the user can place the button where it's the most comfortable to use. +To start scanning, the user can simply tap on it. + +When the scanner is active, the mini preview is shown. The mini preview too can be placed anywhere in the view by simply pressing on it for a little while and then dragging it around. Also the position of the mini preview is remembered across sessions, so the user can place it where it prefers (e.g. not to cover an important information at the top of the app). + +In the default configuration: +- Upon scan the user will receive audio/haptic feedback confirming the scan, and the mini preview will display the scanned barcode for a small amount of time before fading away. +- Tapping on the trigger button or the mini preview will restart immediately the scanner. + +Upon completing the scanning process (or to interact with the customer app layer), the user can tap in any area outside the trigger button and the mini preview. This collapses the scanner button, going back to the initial state. + +If instead of tapping on the trigger button the user taps and holds it pressed, he will be able to scan multiple barcodes in a row. The scanner will stop when the trigger button is released. + +

+ SparkScan Workflow

List building use case using SparkScan. +

+ +The default workflow just described has been carefully designed as a result of extensive user testing and customer feedback from the field. + +But not all use-cases look the same, and your needs may differ for most users. That's why SparkScan comes with a set of options to configure the scanner and to best fit in the desired workflow. Check the [Workflow Options](./advanced.md#workflow-options) guide to discover more. + +## Supported Symbologies + +SparkScan supports all of the major symbologies listed here: [Barcode Symbologies](../barcode-symbologies.mdx). + +## AI-Powered Features + +SparkScan includes AI-powered scanning capabilities that enhance accuracy and user experience. These features automatically handle challenging scenarios such as avoiding unintentional scans, selecting barcodes in dense environments, scanning damaged barcodes with OCR fallback, and intelligently filtering duplicate scans. Learn more about these capabilities in our [AI-Powered Barcode Scanning](../ai-powered-barcode-scanning.md) guide. diff --git a/docs/start.mdx b/docs/start.mdx new file mode 100644 index 0000000000..cff78ef7ea --- /dev/null +++ b/docs/start.mdx @@ -0,0 +1,29 @@ +--- +title: "Not sure which Scandit product? Start here" +description: "Pick what you want to scan and the task you need to do, and go straight to the right Scandit product's docs for your platform." +sidebar_position: 0 +pagination_prev: null +pagination_next: null +keywords: + - get started + - which product + - product chooser + - start here + - scan one item + - stocktake + - order picking + - proof of delivery +--- + +import IntentNavigator from '@site/src/components/IntentNavigator'; + +# Not sure which Scandit product? Start here + +The home page's platform picker assumes you already know your product. This is the other +axis — **pick your intent, get the product** — for the cross-product confusion the replay +and ticket data shows (SparkScan vs Barcode Capture, ID Capture vs ID Bolt…). It is driven +by **one shared intent taxonomy**, the same scan type → task → product map the sign-up quiz +uses, so the docs and sign-up recommend the **same product**. Each recommendation links to +that product's docs for your platform. + + diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000000..a040282299 --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,41 @@ +--- +title: "Troubleshooting: Scandit SDK error messages and fixes" +description: "Paste a Scandit SDK error message to find its cause and fix — licensing, activation, and camera errors." +product: [sparkscan, barcode-capture, id-capture] +topic_type: troubleshooting +version_status: current +canonical_id: scandit.troubleshooting.error-codes +user_intents: + - "find out what a Scandit SDK error message means" + - "fix a Scandit license or activation error" + - "resolve a camera permission error when scanning" +not_for: + - "reporting a new bug — contact support instead" +keywords: + - error + - error code + - license error + - invalid license + - license expired + - troubleshooting + - activation +hide_table_of_contents: true +--- + +import ErrorCodeFinder from '@site/src/components/ErrorCodeFinder'; + +# Troubleshooting: Scandit SDK error messages and fixes + +Hit an error while integrating the SDK? **Paste the exact message from your console** into the box below (or start typing a few words from it). The list narrows to the matching issue with its cause and fix. You can also press Ctrl/Cmd + F to search the page directly. + +Most integration failures are licensing problems — an invalid, expired, or wrong-application key, or the documentation placeholder left in the code. Those are grouped first. + +:::caution Demo preview — sample content +The entries below are **illustrative samples** (each tagged `SAMPLE` with a `SAMPLE-…` code) that demonstrate the finder. They are **not** real Scandit error messages and must not be relied on. Verified messages and fixes will replace them once the support/licensing error data is supplied. +::: + + + +## Still stuck? + +If your error isn't listed, or a fix doesn't resolve it, contact [Scandit support](https://www.scandit.com/support/) with the full console output, your SDK version, and the framework you're using. diff --git a/src/components/ErrorCodeFinder/index.tsx b/src/components/ErrorCodeFinder/index.tsx new file mode 100644 index 0000000000..54c77c64c1 --- /dev/null +++ b/src/components/ErrorCodeFinder/index.tsx @@ -0,0 +1,145 @@ +import React from 'react'; +import Head from '@docusaurus/Head'; +import Link from '@docusaurus/Link'; +import errorData from '@site/src/data/troubleshooting-errors.json'; +import styles from './styles.module.css'; + +/** + * ErrorCodeFinder — the paste-to-filter troubleshooting index (backlog #5). + * + * A reader who hits an SDK error pastes the console message here and the list + * narrows to the matching entry with its cause and fix. Typing a fragment works + * too. A get-started page links here with the input auto-focused so the reader + * can paste immediately; a `?q=` URL param pre-filters (e.g. a deep link). + * + * LLM / GEO retrieval: + * - The full entry list is rendered SERVER-SIDE (not behind BrowserOnly), so + * every message/cause/fix is in the static HTML for crawlers, Algolia, and + * our knowledge-extractor. The search box is progressive enhancement: + * with no JS every entry still shows. + * - Each entry has a stable anchor id, so an answer can cite + * /troubleshooting/#. + * - We emit schema.org FAQPage JSON-LD built from the same catalog, so + * search engines and LLMs get a machine-readable question→answer map. + */ + +interface ErrorEntry { + id: string; + code: string; + area: string; + sample?: boolean; + title: string; + message: string; + match?: string[]; + cause: string; + fix: string; + link?: string; + linkLabel?: string; +} + +const ENTRIES = ((errorData as { entries?: ErrorEntry[] }).entries || []) as ErrorEntry[]; + +function normalize(s: string | undefined): string { + return (s || '').toLowerCase().replace(/\s+/g, ' ').trim(); +} + +/** Match either way: a typed fragment appears in a field, OR the reader pasted + * a whole console line that CONTAINS one of the entry's invariant substrings + * (their own key/app id in the pasted text is ignored this way). */ +function matches(entry: ErrorEntry, nq: string): boolean { + if (!nq) return true; + const fields = [entry.title, entry.code, entry.message, entry.cause, ...(entry.match || [])].map( + normalize, + ); + const forwardHit = fields.some((h) => h && h.includes(nq)); + const invariants = [entry.message, ...(entry.match || [])].map(normalize).filter(Boolean); + const pasteHit = nq.length >= 12 && invariants.some((h) => nq.includes(h)); + return forwardHit || pasteHit; +} + +function buildJsonLd() { + return { + '@context': 'https://schema.org', + '@type': 'FAQPage', + mainEntity: ENTRIES.map((e) => ({ + '@type': 'Question', + name: e.message, + acceptedAnswer: { + '@type': 'Answer', + text: `Cause: ${e.cause} Fix: ${e.fix}`, + }, + })), + }; +} + +export default function ErrorCodeFinder(): JSX.Element { + const [q, setQ] = React.useState(''); + const inputRef = React.useRef(null); + + React.useEffect(() => { + try { + const fromQuery = new URLSearchParams(window.location.search).get('q') || ''; + if (fromQuery) setQ(fromQuery); + } catch { + /* SSR / no window */ + } + inputRef.current?.focus(); + }, []); + + const nq = normalize(q); + const visible = ENTRIES.filter((e) => matches(e, nq)); + + return ( +
+ + + + + setQ(e.target.value)} + placeholder="Paste your error message here, or start typing…" + aria-label="Search Scandit error messages" + spellCheck={false} + autoComplete="off" + /> +

+ {q ? `${visible.length} of ${ENTRIES.length} matching` : `${ENTRIES.length} known issues`} +

+ + {visible.length === 0 && ( +

+ No match yet. Try pasting a shorter part of the message, or search the full documentation. +

+ )} + +
    + {visible.map((e) => ( +
  • +
    + {e.area} + {e.sample && SAMPLE} + {e.code} +
    +

    {e.title}

    +
    {e.message}
    +

    + Cause: {e.cause} +

    +

    + Fix: {e.fix} +

    + {e.link && ( + + {e.linkLabel || 'Learn more'} → + + )} +
  • + ))} +
+
+ ); +} diff --git a/src/components/ErrorCodeFinder/styles.module.css b/src/components/ErrorCodeFinder/styles.module.css new file mode 100644 index 0000000000..7105438ff3 --- /dev/null +++ b/src/components/ErrorCodeFinder/styles.module.css @@ -0,0 +1,114 @@ +.finder { + margin: 1.5rem 0 2rem; +} + +.search { + width: 100%; + box-sizing: border-box; + font-size: 1rem; + padding: 0.7rem 0.9rem; + border: 2px solid var(--ifm-color-emphasis-300); + border-radius: 10px; + background: var(--ifm-background-surface-color); + color: var(--ifm-font-color-base); +} + +.search:focus { + outline: none; + border-color: var(--ifm-color-primary); +} + +.count { + margin: 0.5rem 0 1rem; + font-size: 0.8rem; + font-weight: 600; + letter-spacing: 0.02em; + text-transform: uppercase; + color: var(--ifm-color-emphasis-600); +} + +.empty { + padding: 1rem 1.1rem; + border: 1px dashed var(--ifm-color-emphasis-300); + border-radius: 10px; + color: var(--ifm-color-emphasis-700); +} + +.list { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 1rem; +} + +.card { + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 10px; + padding: 1rem 1.25rem 1.1rem; + background: var(--ifm-background-surface-color); + scroll-margin-top: 5rem; +} + +.head { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 0.5rem; + margin-bottom: 0.4rem; +} + +.area { + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.05em; + text-transform: uppercase; + color: var(--ifm-color-emphasis-600); +} + +.sampleTag { + font-size: 0.66rem; + font-weight: 800; + letter-spacing: 0.08em; + padding: 0.1rem 0.4rem; + border-radius: 4px; + background: var(--ifm-color-warning-contrast-background); + color: var(--ifm-color-warning-darker); + border: 1px solid var(--ifm-color-warning); +} + +.code { + margin-left: auto; + font-size: 0.74rem; + color: var(--ifm-color-emphasis-600); +} + +.title { + margin: 0 0 0.5rem; + font-size: 1.05rem; +} + +.message { + margin: 0 0 0.7rem; + padding: 0.5rem 0.8rem; + border-left: 3px solid var(--ifm-color-danger); + background: var(--ifm-color-emphasis-100); + font-family: var(--ifm-font-family-monospace); + font-size: 0.85rem; + color: var(--ifm-font-color-base); + border-radius: 0 6px 6px 0; +} + +.line { + margin: 0.3rem 0; + font-size: 0.92rem; + line-height: 1.5; +} + +.link { + display: inline-block; + margin-top: 0.5rem; + font-size: 0.9rem; + font-weight: 600; +} diff --git a/src/components/IntentNavigator/index.tsx b/src/components/IntentNavigator/index.tsx new file mode 100644 index 0000000000..9e55fc5c2f --- /dev/null +++ b/src/components/IntentNavigator/index.tsx @@ -0,0 +1,405 @@ +import React from 'react'; +import Link from '@docusaurus/Link'; +import intents from '@site/src/data/intents.json'; +import productsData from '@site/src/data/products.json'; +import styles from './styles.module.scss'; + +/** + * IntentNavigator — the "Start here / I want to…" entry point. + * + * Renders the same intent taxonomy as the Unified-Signup PRD product quiz + * (scan type → task → delivery → product), so the docs and the signup flow route + * the same intent to the same product. Every recommendation links to that + * product's docs on the reader's chosen platform. + * + * Ported from the Phase E demo, keeping its full structure and grouping: + * 1. platform bar — pick your platform, remembered between visits + * 2. expert shortcut — "Already know your product? Jump straight in →" + * 3. three numbered steps with progressive disclosure, plus "start over" + * 4. "Why this matters" — docs ↔ signup parity + * 5. the Linux caveat, and a provenance footer + * + * Two deliberate differences from the demo: + * + * - COLOURS COME FROM THE SITE, NOT A PRIVATE PALETTE. The demo carried its own + * hex values; here every colour is an existing docs token so the component + * matches the surrounding page and follows the site's light/dark toggle. + * + * - AVAILABILITY IS COMPUTED, NOT COPIED. The demo hard-coded a PROD table + * "derived verbatim from products.json"; a copy drifts the moment products.json + * changes, so this reads products.json directly. Only the two things genuinely + * absent from that file are declared here (hosted products, and Linux). + * + * Disclosure is done with CSS, exactly as the demo did it, NOT by conditional + * rendering — which matters for two reasons. There is no flash of a different + * layout before hydration, because the server already renders the stepped UI. And + * every task phrasing and every product link is present in the static HTML, so + * search, crawlers and the AI retrieval layer see the whole taxonomy even though + * the reader is shown one step at a time. A React-state-gated render would have + * hidden all of it from them. + * + * With no JavaScript the step buttons cannot do anything, so a