> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getkardy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Staff guide

> A practical shift guide to joining your team, scanning members, and redeeming rewards.

export const GuidePractice = ({questions}) => {
  const [step, setStep] = useState(0);
  const [answer, setAnswer] = useState(null);
  const question = questions[step];
  const correct = answer === question.correct;
  return <section className="kardy-guide kardy-guide-practice" aria-label="Practice a real situation">
      <div className="kardy-guide-heading">
        <div>
          <span className="kardy-guide-kicker">TRY IT SAFELY</span>
          <h3>What would you do?</h3>
        </div>
        <span className="kardy-guide-count">
          {step + 1} / {questions.length}
        </span>
      </div>
      <p className="kardy-guide-question">{question.prompt}</p>
      <div className="kardy-guide-answers" role="group" aria-label="Choose an answer">
        {question.options.map((option, index) => <button key={`${step}-${index}`} type="button" aria-pressed={answer === index} onClick={() => setAnswer(index)}>
            <span aria-hidden="true">{String.fromCharCode(65 + index)}</span>
            {option}
          </button>)}
      </div>
      <div role="status" aria-live="polite">
        {answer !== null && <div className="kardy-guide-feedback" data-correct={correct}>
            <strong>{correct ? "That’s right." : "Not quite."}</strong>
            <p>{question.explanation}</p>
          </div>}
      </div>
      <div className="kardy-guide-footer">
        <small>Practice only. No stamps, claims or account changes.</small>
        <button type="button" className="kardy-guide-next" disabled={answer === null} onClick={() => {
    setStep((step + 1) % questions.length);
    setAnswer(null);
  }}>
          {step === questions.length - 1 ? "Practise again" : "Next situation"}
          <span aria-hidden="true"> →</span>
        </button>
      </div>
    </section>;
};

export const GuideChecklist = ({guide, title, items}) => {
  const [checked, setChecked] = useState([]);
  const [storage, setStorage] = useState("Progress stays in this browser only.");
  useEffect(() => {
    try {
      const value = JSON.parse(localStorage.getItem(`kardy-guide-v1:${guide}`) || "[]");
      setChecked(Array.isArray(value) ? [...new Set(value.filter(i => Number.isInteger(i) && i >= 0 && i < items.length))] : []);
    } catch {
      setStorage("Browser storage is unavailable. Progress lasts until you leave this page.");
    }
  }, [guide, items.length]);
  const save = next => {
    setChecked(next);
    try {
      localStorage.setItem(`kardy-guide-v1:${guide}`, JSON.stringify(next));
    } catch {
      setStorage("Browser storage is unavailable. Progress lasts until you leave this page.");
    }
  };
  return <section className="kardy-guide" aria-label={title}>
      <div className="kardy-guide-heading">
        <div>
          <span className="kardy-guide-kicker">YOUR CHECKLIST</span>
          <h3>{title}</h3>
        </div>
        <span className="kardy-guide-count" role="status">
          {checked.length} / {items.length}
        </span>
      </div>
      <progress aria-label={`${title} progress`} max={items.length} value={checked.length} />
      <div className="kardy-guide-tasks">
        {items.map((item, index) => <button type="button" key={item} className="kardy-guide-task t-check" role="checkbox" aria-checked={checked.includes(index)} onClick={() => save(checked.includes(index) ? checked.filter(i => i !== index) : [...checked, index])}>
            <span className="kardy-guide-box" aria-hidden="true">
              <svg viewBox="0 0 10.1668 10.1668">
                <path ref={path => {
    if (path) path.style.setProperty("--check-len", String(Math.ceil(path.getTotalLength())));
  }} d="M1 5.52L3.92 9.17L9.17 1" />
              </svg>
            </span>
            <span>{item}</span>
          </button>)}
      </div>
      <div className="kardy-guide-footer">
        <small>
          {checked.length === items.length ? "Checklist complete. This is a personal reminder, not a system readiness check." : storage}
        </small>
        <button type="button" className="kardy-guide-reset" onClick={() => save([])} disabled={!checked.length}>
          Reset checklist
        </button>
      </div>
    </section>;
};

Staff help customers collect stamps and claim rewards. Use your own invited
account; you do not need the Owner's credentials to work at the counter.

## Before your shift

<GuideChecklist
  guide="staff"
  title="Your shift, ready to go"
  items={[
"I accepted my invitation with my own verified email.",
"I checked the selected organisation.",
"I selected the outlet where I am serving customers.",
"My Manager confirmed which purchases qualify and what rewards include.",
]}
/>

## Work the counter

Follow [Scan, stamp, and redeem](/merchants/scanning) for the complete workflow.
Choose **Check membership** first, then **Add stamp** for a qualifying purchase. Checking lets you inspect
a reward without adding progress. Wait for confirmation before serving the next
customer; a lost response does not prove the operation failed.

## Practise the counter flow

Choose an answer to see why it matters. These examples use fictional situations.

<GuidePractice
  questions={[
{
  prompt:
    "A customer only wants to know whether their reward is ready. What do you choose?",
  options: ["Add stamp", "Check membership", "Redeem without checking"],
  correct: 1,
  explanation:
    "Check membership reads the balance without adding a stamp. Only issue stamps for qualifying purchases.",
},
{
  prompt:
    "You submitted a stamp, but the connection dropped before the result appeared. What next?",
  options: [
    "Submit three more times",
    "Assume it failed",
    "Check the current balance and activity before retrying",
  ],
  correct: 2,
  explanation:
    "A network error does not prove the write failed. Check the result first to avoid recording the visit again.",
},
{
  prompt:
    "A friend joins through a referral link but has not purchased anything. Are the referral bonuses awarded?",
  options: [
    "Yes, signing up is enough",
    "Not until the first qualifying purchase and first staff-issued stamp",
    "Only after a reward is redeemed",
  ],
  correct: 1,
  explanation:
    "Joining alone awards no bonus. The first qualifying purchase, recorded by a staff-issued stamp, triggers the configured bonuses; redeeming a reward is not required.",
},
]}
/>

## When to ask for help

Use the [scanning troubleshooting checks](/merchants/scanning#when-something-goes-wrong).
Ask your Manager about reward eligibility and the Owner about access or activation.
Do not promise an undo or remove event history to hide a mistake.

## Your access

Staff can perform authorised member and loyalty operations. Staff cannot change
programme configuration, manage teammates, transfer ownership, access broadcasts,
or manage billing. Ask your Manager about programme changes and your Owner about
access changes. See [the role comparison](/accounts/overview#who-can-do-what).

Never request a customer's password, verification code, or reset link. Keep their
QR private and sign out when you finish using a shared device.
