// Sitter Onboarding — 6-step registration flow. // Interactive: stepper at top, prev/next, fields editable. function SitterRegister({ initialStep = 0 }) { const [step, setStep] = React.useState(initialStep); const [form, setForm] = React.useState({ pets: ['dog'], exp: 3, skills: ['walk', 'med'], serviceTypes: ['visit'], rate: 3200, days: ['mon','tue','wed','thu','fri'], bio: '', idVerified: true, cert: 'pet-care-2', area: '107-0062 港区南青山', stations: ['表参道','外苑前'], // 動物取扱責任者 licStatus: 'none', // 'have' | 'none' licNumber: '', licCategory: 'hokan', // 保管 / 訓練 / 展示 licPrefecture: '', licHolderName: '', licAgree: false, // ソプラ銀座との業務委託合意 // 写真 profilePhoto: null, // File | null idDocument: null, // File | null(身分証) selfie: null, // File | null // 規約系 insAgree: false, tosAgree: false, }); const set = (k, v) => setForm(f => ({ ...f, [k]: v })); const toggle = (k, v) => setForm(f => ({ ...f, [k]: f[k].includes(v) ? f[k].filter(x => x !== v) : [...f[k], v] })); const steps = [ ['基本情報','01'], ['対応ペット','02'], ['経験・資格','03'], ['サービス内容','04'], ['料金・空き状況','05'], ['プロフィール','06'], ['本人確認','07'], ]; const next = () => setStep(s => Math.min(s + 1, steps.length - 1)); const prev = () => setStep(s => Math.max(s - 1, 0)); // 送信状態:idle / loading / success / error const [submitState, setSubmitState] = React.useState({ phase: 'idle', message: '' }); const submit = async () => { setSubmitState({ phase: 'loading', message: '送信中…' }); // form → webhook data 形式へ整形(File ではない値のみ) const data = { lastName: form.lastName || '', firstName: form.firstName || '', nickname: form.nickname || '', birthDate: form.birthDate || '', gender: form.gender || '', email: form.email || '', phone: form.phone || '', area: form.area || '', stations: form.stations || [], pets: form.pets || [], exp: form.exp || 0, cert: form.cert || '', skills: form.skills || [], serviceTypes: form.serviceTypes || [], rate: form.rate || 0, days: form.days || [], bio: form.bio || '', licStatus: form.licStatus || 'none', licNumber: form.licNumber || '', licCategory: form.licCategory || '', licPrefecture: form.licPrefecture || '', licHolderName: form.licHolderName || '', idVerified: !!(form.idDocument && form.selfie), }; const res = await window.palpetSubmitRegistration({ type: 'sitter', data, photos: [ ['profilePhoto', form.profilePhoto], ['idDocument', form.idDocument], ['selfie', form.selfie], ], }); if (res.ok) { setSubmitState({ phase: 'success', message: res.demo ? 'デモ送信が完了しました(実際の通知は行われていません)。' : `送信完了。受付ID: ${res.row?.id || '—'}。1〜2営業日でご連絡します。`, res, }); } else { setSubmitState({ phase: 'error', message: res.message || res.error || '送信に失敗しました。', res, }); } }; return (
{/* Top nav */}
palpet
シッター登録 ・ 進捗を保存しました
あとで再開
{/* Stepper rail */} {/* Main form area */}
{/* Progress bar */}
{step === 0 && } {step === 1 && } {step === 2 && } {step === 3 && } {step === 4 && } {step === 5 && } {step === 6 && } {/* 送信状態フィードバック */} {submitState.phase !== 'idle' && ( setSubmitState({phase:'idle',message:''})}/> )}
{/* Preview rail */}
); } // ---------- Step bodies ---------- const SectionH = ({n, t, sub}) => (
STEP {n}

{t}

{sub &&
{sub}
}
); const Field = ({label, hint, children, half}) => (
{label}
{children} {hint &&
{hint}
}
); const inputCss = { width:'100%',padding:'14px 16px',borderRadius:14, border:'1.5px solid rgba(0,0,0,.08)',background:'#fff', fontSize:15,fontFamily:'inherit',color:'#2E2418',outline:'none', }; function Step0({form, set, toggle}) { return (<>
{['女性','男性','その他'].map((g,i)=>( ))}
set('area',e.target.value)}/> toggle('stations',s)}/>
); } // 駅選択 — エリアからのサジェスト + 自由入力で追加 function StationPicker({ stations, onToggle }) { const [q, setQ] = React.useState(''); const suggestions = [ '表参道','外苑前','青山一丁目','広尾','六本木','乃木坂', '赤坂','麻布十番','白金高輪','恵比寿','渋谷','原宿', ]; const filtered = q.trim() ? suggestions.filter(s => s.includes(q.trim()) && !stations.includes(s)) : suggestions.filter(s => !stations.includes(s)); const addCustom = () => { const v = q.trim(); if (!v) return; if (!stations.includes(v)) onToggle(v); setQ(''); }; return (
{/* 選択済みチップ */}
{stations.length === 0 && ( まだ駅が選ばれていません )} {stations.map(s => ( {s}駅 ))}
{/* 検索 + 追加 */}
setQ(e.target.value)} onKeyDown={e=>{ if(e.key==='Enter'){ e.preventDefault(); addCustom(); }}} placeholder="駅名で検索/追加(例:表参道)" style={{ flex:1,padding:'10px 14px',borderRadius:10, border:'1.5px solid rgba(0,0,0,.08)',background:'var(--c-bg)', fontSize:14,fontFamily:'inherit',color:'#2E2418',outline:'none', }} />
{/* サジェスト */}
このエリアの近隣駅
{filtered.length === 0 && ( 候補がありません )} {filtered.map(s => ( ))}
); } function Step1({form, toggle}) { const pets = [ ['dog','犬',PetGlyph.Dog,'小型〜大型'], ['cat','猫',PetGlyph.Cat,'室内・外猫'], ['rabbit','うさぎ',PetGlyph.Rabbit,'小動物全般'], ['bird','鳥','🐦','小鳥・インコ'], ['reptile','爬虫類','🦎','カメ・トカゲ'], ['fish','魚','🐟','給餌・水替え'], ]; return (<>
{pets.map(([k,n,G,d])=>{ const sel = form.pets.includes(k); return ( ); })}
); } function Step2({form, set, toggle}) { const skills = [ ['walk','散歩経験','長距離・複数頭OK'], ['med','投薬','錠剤・注射対応'], ['groom','ブラッシング',null], ['behavior','問題行動への対応',null], ['senior','シニアペットケア',null], ['kitten','子犬・子猫ケア',null], ]; return (<>
1年 {form.exp}年 20年+
set('exp',+e.target.value)} style={{width:'100%',accentColor:'var(--c-primary)'}}/>
{/* ソプラアカデミー CTA — 資格なし or 経験未確認の人向け */} {(form.cert === '' || form.cert === 'none') && ( )}
得意なお世話(複数選択可)
{skills.map(([k,n,sub])=>{ const sel = form.skills.includes(k); return ( ); })}
{/* 動物取扱責任者 */}
動物取扱責任者の資格
ペットシッター業(保管)には動物取扱業の登録が必要です。お持ちかどうか教えてください。
{[ ['have','登録あり','動物取扱責任者として登録済み'], ['none','登録なし','業務委託契約でカバーできます'], ].map(([k,n,d])=>{ const sel = form.licStatus === k; return ( ); })}
{form.licStatus === 'have' && (
set('licNumber',e.target.value)}/> set('licPrefecture',e.target.value)}/> set('licHolderName',e.target.value)}/>
登録証のコピーは「本人確認」ステップでアップロードしてください。
)} {form.licStatus === 'none' && (
ソプラ銀座株式会社と業務委託契約を結びます
動物取扱責任者の資格をお持ちでないシッターは、運営元の ソプラ銀座株式会社(動物取扱業登録:13東京都動セ第◯◯号/保管)と 業務委託契約を結ぶことで、合法的にお仕事ができます。手続きはオンラインで完結し、 登録費・年会費は無料です。
  • 運営会社のスタッフとして、研修・サポートを受けられます
  • 事故・損害保険は運営会社の包括契約でカバーされます
  • 動物取扱責任者の資格取得を希望する場合、研修への参加もご案内します
{/* ソプラアカデミー CTA — 業務委託で進む人にも将来の資格取得を案内 */}
)}
); } // ----------------- ソプラアカデミー CTA ----------------- function AcademyCTA({ compact, context }) { const academy = (typeof window !== 'undefined' && window.SOPRA_ACADEMY); if (!academy) return null; const headline = context === 'license' ? '将来的に資格を取得して責任者になりたい方は' : '資格がなくても、ソプラアカデミーで取得できます'; const sub = context === 'license' ? '業務委託契約で活動しながら、ソプラアカデミーで動物取扱責任者の要件を満たす資格取得も可能です。' : 'JPLC認定の通信講座。在宅・最短2ヶ月で取得でき、副業からプロまで対応。'; return (
🎓
SOPRA ACADEMY
{headline}
{sub}
{academy.courses.map(c=>(
{c.badge && ( {c.badge} )}
{c.name.replace(/ペットシッター/,'').trim() || c.name}
¥{c.price.toLocaleString()} 税込
))}
資格講座を見る ↗ 在宅・最短2ヶ月・JPLC認定
); } function Step3({form, toggle}) { const types = [ ['visit','訪問ケア','飼い主様のお宅にお伺いします',Icons.Pin], ['walk','お散歩のみ','お家までお迎えに行きます',Icons.Sparkle], ['stay','お預かり(自宅)','シッターの自宅でお預かり',Icons.Heart], ['overnight','お泊まり','宿泊を含む長時間のケア',Icons.Calendar], ]; return (<>
{types.map(([k,n,d,I])=>{ const sel = form.serviceTypes.includes(k); return ( ); })}
); } function Step4({form, set, toggle}) { const days = [['mon','月'],['tue','火'],['wed','水'],['thu','木'],['fri','金'],['sat','土'],['sun','日']]; const pricing = (typeof window !== 'undefined' && window.PALPET_PRICING) || { base:{ '60':3300 } }; return (<> {/* 統一料金の説明 */}
料金はパルペットで統一されています
19年のペットケア実績を持つソプラ銀座が運営するため、シッター間で料金を競わせる必要はありません。 人材の質を担保しているからこそ、すべてのシッターに同じ料金が支払われます。
{(pricing.plans?.standard?.tiers || []).map((tier)=>(
{tier.minutes}分
¥{tier.price.toLocaleString()}
))}
※ 税込・1回の訪問あたり(基本ペットシッタープラン)。延長30分毎 ¥3,000。 ロング・深夜・定額プランも別途あります。
別途交通費(同区内 ¥500目安)。シッターへの報酬は別の料金表で公開されています。
{days.map(([k,n])=>{ const sel = form.days.includes(k); return ( ); })}
); } function Step5({form, set}) { return (<> set('profilePhoto', f)} title="顔がはっきり写った写真を1枚" hint="笑顔の写真、ペットと一緒の写真はよりおすすめ。サングラスは不可です(5MB以内・JPEG/PNG)。" sampleTone="warm"/>