on screen keyboard v1

This commit is contained in:
Raika Furude 2025-11-20 11:15:03 -05:00
parent 5d477142d6
commit ad267720ed
5 changed files with 456 additions and 2153 deletions

View File

@ -15,6 +15,8 @@ function App() {
const [assignedBand, setAssignedBand] = useState(null);
const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState(null);
const [showKeyboard, setShowKeyboard] = useState(false);
const [activeField, setActiveField] = useState(null);
const symptoms = [
'Chest Pain', 'Difficulty Breathing', 'Severe Headache',
@ -31,6 +33,40 @@ function App() {
}));
};
const handleKeyPress = (key) => {
if (!activeField) return;
if (key === 'BACKSPACE') {
setFormData(prev => ({
...prev,
[activeField]: prev[activeField].slice(0, -1)
}));
} else if (key === 'SPACE') {
setFormData(prev => ({
...prev,
[activeField]: prev[activeField] + ' '
}));
} else if (key === 'CLEAR') {
setFormData(prev => ({
...prev,
[activeField]: ''
}));
} else if (key === 'DONE') {
setShowKeyboard(false);
setActiveField(null);
} else {
setFormData(prev => ({
...prev,
[activeField]: prev[activeField] + key
}));
}
};
const handleInputFocus = (fieldName) => {
setActiveField(fieldName);
setShowKeyboard(true);
};
const handleSubmit = async () => {
setIsSubmitting(true);
setError(null);
@ -60,6 +96,7 @@ function App() {
});
setStep('complete');
setShowKeyboard(false);
} catch (error) {
console.error('Check-in failed:', error);
setError(error.message);
@ -85,21 +122,21 @@ function App() {
<h2 className="font-semibold text-lg text-gray-800 mb-3">What to expect:</h2>
<div className="flex items-start gap-3">
<CheckCircle className="w-5 h-5 text-green-600 mt-1 flex-shrink-0" />
<p className="text-gray-700">Answer a few questions about your condition</p>
<p className="text-gray-700 text-lg">Answer a few questions about your condition</p>
</div>
<div className="flex items-start gap-3">
<CheckCircle className="w-5 h-5 text-green-600 mt-1 flex-shrink-0" />
<p className="text-gray-700">Receive a smart wristband to monitor your vitals</p>
<p className="text-gray-700 text-lg">Receive a smart wristband to monitor your vitals</p>
</div>
<div className="flex items-start gap-3">
<CheckCircle className="w-5 h-5 text-green-600 mt-1 flex-shrink-0" />
<p className="text-gray-700">Wait comfortably while we track your condition</p>
<p className="text-gray-700 text-lg">Wait comfortably while we track your condition</p>
</div>
</div>
<button
onClick={() => setStep('form')}
className="bg-blue-600 text-white px-12 py-4 rounded-xl text-xl font-semibold hover:bg-blue-700 transition-colors shadow-lg"
className="bg-blue-600 text-white px-16 py-6 rounded-xl text-2xl font-bold hover:bg-blue-700 transition-colors shadow-lg active:scale-95"
>
Start Check-In
</button>
@ -110,7 +147,7 @@ function App() {
if (step === 'form') {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-blue-100 p-4">
<div className={`min-h-screen bg-gradient-to-br from-blue-50 to-blue-100 p-4 ${showKeyboard ? 'pb-96' : ''}`}>
<div className="max-w-3xl mx-auto pt-8">
<div className="bg-white rounded-2xl shadow-2xl p-8">
<h2 className="text-3xl font-bold text-gray-800 mb-6">Patient Information</h2>
@ -133,9 +170,10 @@ function App() {
<input
type="text"
value={formData.firstName}
onChange={(e) => setFormData({...formData, firstName: e.target.value})}
className="w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none text-lg"
placeholder="John"
onFocus={() => handleInputFocus('firstName')}
readOnly
className="w-full px-6 py-4 border-2 border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none text-xl font-semibold cursor-pointer bg-white"
placeholder="Tap to type"
/>
</div>
<div>
@ -145,9 +183,10 @@ function App() {
<input
type="text"
value={formData.lastName}
onChange={(e) => setFormData({...formData, lastName: e.target.value})}
className="w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none text-lg"
placeholder="Doe"
onFocus={() => handleInputFocus('lastName')}
readOnly
className="w-full px-6 py-4 border-2 border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none text-xl font-semibold cursor-pointer bg-white"
placeholder="Tap to type"
/>
</div>
</div>
@ -160,7 +199,7 @@ function App() {
type="date"
value={formData.dob}
onChange={(e) => setFormData({...formData, dob: e.target.value})}
className="w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none text-lg"
className="w-full px-6 py-4 border-2 border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none text-xl font-semibold"
/>
</div>
@ -174,7 +213,7 @@ function App() {
key={symptom}
onClick={() => handleSymptomToggle(symptom)}
type="button"
className={`px-4 py-3 rounded-lg border-2 transition-all text-left font-medium ${
className={`px-6 py-5 rounded-lg border-2 transition-all text-left font-semibold text-lg active:scale-95 ${
formData.symptoms.includes(symptom)
? 'bg-blue-100 border-blue-500 text-blue-700'
: 'bg-white border-gray-300 text-gray-700 hover:border-blue-300'
@ -196,7 +235,7 @@ function App() {
key={level}
onClick={() => setFormData({...formData, severity: level})}
type="button"
className={`px-6 py-4 rounded-lg border-2 transition-all font-semibold capitalize ${
className={`px-8 py-6 rounded-lg border-2 transition-all font-bold capitalize text-xl active:scale-95 ${
formData.severity === level
? level === 'severe'
? 'bg-red-100 border-red-500 text-red-700'
@ -217,7 +256,7 @@ function App() {
<button
onClick={() => setStep('welcome')}
type="button"
className="flex-1 px-6 py-4 border-2 border-gray-300 text-gray-700 rounded-xl font-semibold hover:bg-gray-50 transition-colors"
className="flex-1 px-8 py-5 border-2 border-gray-300 text-gray-700 rounded-xl text-xl font-bold hover:bg-gray-50 transition-colors active:scale-95"
>
Back
</button>
@ -225,13 +264,82 @@ function App() {
onClick={handleSubmit}
disabled={!formData.firstName || !formData.lastName || !formData.dob || formData.symptoms.length === 0 || isSubmitting}
type="button"
className="flex-1 px-6 py-4 bg-blue-600 text-white rounded-xl font-semibold hover:bg-blue-700 transition-colors disabled:bg-gray-300 disabled:cursor-not-allowed"
className="flex-1 px-8 py-5 bg-blue-600 text-white rounded-xl text-xl font-bold hover:bg-blue-700 transition-colors disabled:bg-gray-300 disabled:cursor-not-allowed active:scale-95"
>
{isSubmitting ? 'Checking In...' : 'Complete Check-In'}
</button>
</div>
</div>
</div>
{/* On-Screen Keyboard - ONLY ONE DECLARATION */}
{showKeyboard && (
<div className="fixed bottom-0 left-0 right-0 bg-gradient-to-t from-gray-900 to-gray-800 border-t-4 border-blue-500 shadow-2xl p-6 z-50">
<div className="max-w-5xl mx-auto">
<div className="flex justify-between items-center mb-4">
<div className="text-white">
<p className="text-sm opacity-75">Currently typing:</p>
<p className="font-bold text-xl">
{activeField === 'firstName' ? 'First Name' : 'Last Name'}
</p>
</div>
<div className="bg-gray-700 px-6 py-3 rounded-lg">
<p className="text-white font-mono text-2xl min-w-[200px]">
{formData[activeField] || '_'}
</p>
</div>
</div>
<div className="space-y-3">
{[
['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'],
['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'],
['Z', 'X', 'C', 'V', 'B', 'N', 'M', 'BACKSPACE'],
['SPACE', 'CLEAR', 'DONE']
].map((row, rowIndex) => (
<div key={rowIndex} className="flex gap-2 justify-center">
{row.map((key) => {
const isDone = key === 'DONE';
const isBackspace = key === 'BACKSPACE';
const isSpace = key === 'SPACE';
const isClear = key === 'CLEAR';
return (
<button
key={key}
onClick={() => handleKeyPress(key)}
className={`
font-bold rounded-xl transition-all active:scale-95 shadow-lg
${isDone
? 'bg-green-600 text-white hover:bg-green-700 px-12 py-5 text-xl'
: isBackspace
? 'bg-red-600 text-white hover:bg-red-700 px-8 py-5 text-xl'
: isSpace
? 'bg-gray-600 text-white hover:bg-gray-700 px-32 py-5'
: isClear
? 'bg-orange-600 text-white hover:bg-orange-700 px-8 py-5'
: 'bg-blue-600 text-white hover:bg-blue-700 min-w-[60px] py-5 text-2xl'
}
`}
>
{key === 'BACKSPACE' ? '⌫ Delete' :
key === 'SPACE' ? '_____ Space _____' :
key === 'CLEAR' ? '✕ Clear' :
key === 'DONE' ? '✓ Done' :
key}
</button>
);
})}
</div>
))}
</div>
<p className="text-center text-gray-400 text-sm mt-4">
Tap any key to type Tap Done when finished
</p>
</div>
</div>
)}
</div>
);
}
@ -261,27 +369,27 @@ function App() {
<h2 className="font-bold text-lg text-gray-800 mb-3">Next Steps:</h2>
<div className="flex items-start gap-3">
<div className="bg-blue-600 text-white rounded-full w-8 h-8 flex items-center justify-center font-bold flex-shrink-0">1</div>
<p className="text-gray-700 pt-1">
<p className="text-gray-700 pt-1 text-lg">
<strong>Pick up your wristband</strong> from Station {assignedBand?.station}
</p>
</div>
<div className="flex items-start gap-3">
<div className="bg-blue-600 text-white rounded-full w-8 h-8 flex items-center justify-center font-bold flex-shrink-0">2</div>
<p className="text-gray-700 pt-1">
<p className="text-gray-700 pt-1 text-lg">
<strong>Wear it on your wrist</strong> - make sure it's snug but comfortable
</p>
</div>
<div className="flex items-start gap-3">
<div className="bg-blue-600 text-white rounded-full w-8 h-8 flex items-center justify-center font-bold flex-shrink-0">3</div>
<p className="text-gray-700 pt-1">
<p className="text-gray-700 pt-1 text-lg">
<strong>Take a seat in the waiting area</strong> - your vitals are being monitored
</p>
</div>
</div>
<div className="flex items-center justify-center gap-2 text-gray-600 mb-6">
<Clock className="w-5 h-5" />
<p>A nurse will call you when it's your turn</p>
<Clock className="w-6 h-6" />
<p className="text-lg">A nurse will call you when it's your turn</p>
</div>
<button
@ -291,7 +399,7 @@ function App() {
setAssignedBand(null);
setError(null);
}}
className="text-blue-600 font-semibold hover:underline"
className="text-blue-600 text-xl font-bold hover:underline"
>
Return to Start
</button>

File diff suppressed because it is too large Load Diff

View File

@ -3,12 +3,7 @@
> vite
VITE v7.1.10 ready in 393 ms
VITE v7.1.10 ready in 220 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
npm notice
npm notice New patch version of npm available! 11.6.2 -> 11.6.3
npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.6.3
npm notice To update run: npm install -g npm@11.6.3
npm notice

View File

@ -4,7 +4,7 @@
Port 5173 is in use, trying another one...
VITE v7.1.10 ready in 371 ms
VITE v7.1.10 ready in 228 ms
➜ Local: http://localhost:5174/
➜ Network: use --host to expose

View File

@ -1,133 +0,0 @@
⚠️ Bleak not installed. Real wristbands disabled. Install with: pip install bleak
✓ Loaded configuration from wristband_config.yaml
================================================================================
VitalLink System Initialization
================================================================================
✓ Backend is running at http://localhost:8000
Added simulated band MOCK-SIM1 (stable)
Added simulated band MOCK-SIM2 (mild_anxiety)
Added simulated band MOCK-SIM3 (deteriorating)
Added simulated band MOCK-SIM4 (sepsis)
================================================================================
WRISTBAND INVENTORY
================================================================================
🟢 MOCK-SIM1 | AVAILABLE
🟢 MOCK-SIM2 | AVAILABLE
🟢 MOCK-SIM3 | AVAILABLE
🟢 MOCK-SIM4 | AVAILABLE
================================================================================
Total: 4 | Real: 0 | Simulated: 4 | Active: 0
================================================================================
================================================================================
VitalLink System Running
================================================================================
✓ Monitoring for new patients from kiosk check-ins
✓ Auto-assigning wristbands (prefer real: False)
Press Ctrl+C to stop
================================================================================
🔍 Monitoring for new patient check-ins...
[Status] Active: 0 monitoring | Available: 4 bands | Real: 0 | Sim: 4
[Status] Active: 0 monitoring | Available: 4 bands | Real: 0 | Sim: 4
[Status] Active: 0 monitoring | Available: 4 bands | Real: 0 | Sim: 4
[Status] Active: 0 monitoring | Available: 4 bands | Real: 0 | Sim: 4
🆕 New patient detected: P100001 (Andrew Hartley)
✓ MOCK-SIM1 assigned to patient P100001
✓ Assigned MOCK-SIM1 (simulated)
🟢 Starting simulated wristband MOCK-SIM1 (stable)
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4
[Status] Active: 1 monitoring | Available: 3 bands | Real: 0 | Sim: 4