better keyboard better gui simplekeyboard
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useRef } from 'react';
|
||||
import { AlertCircle, CheckCircle, Clock, User } from 'lucide-react';
|
||||
import Keyboard from "react-simple-keyboard";
|
||||
import "react-simple-keyboard/build/css/index.css";
|
||||
|
||||
const API_BASE = 'http://localhost:8000';
|
||||
|
||||
@@ -17,6 +19,8 @@ function App() {
|
||||
const [error, setError] = useState(null);
|
||||
const [showKeyboard, setShowKeyboard] = useState(false);
|
||||
const [activeField, setActiveField] = useState(null);
|
||||
const [layoutName, setLayoutName] = useState("default");
|
||||
const keyboard = useRef();
|
||||
|
||||
const symptoms = [
|
||||
'Chest Pain', 'Difficulty Breathing', 'Severe Headache',
|
||||
@@ -33,38 +37,31 @@ function App() {
|
||||
}));
|
||||
};
|
||||
|
||||
const handleKeyPress = (key) => {
|
||||
if (!activeField) return;
|
||||
const onKeyboardChange = (input) => {
|
||||
if (activeField) {
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[activeField]: input
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
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') {
|
||||
const onKeyPress = (button) => {
|
||||
if (button === "{shift}" || button === "{lock}") {
|
||||
setLayoutName(layoutName === "default" ? "shift" : "default");
|
||||
}
|
||||
if (button === "{close}") {
|
||||
setShowKeyboard(false);
|
||||
setActiveField(null);
|
||||
} else {
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[activeField]: prev[activeField] + key
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
const handleInputFocus = (fieldName) => {
|
||||
setActiveField(fieldName);
|
||||
setShowKeyboard(true);
|
||||
if (keyboard.current) {
|
||||
keyboard.current.setInput(formData[fieldName]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
@@ -72,8 +69,6 @@ function App() {
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
console.log('Submitting check-in data:', formData);
|
||||
|
||||
const response = await fetch(`${API_BASE}/api/checkin`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -87,7 +82,6 @@ function App() {
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('Check-in successful:', data);
|
||||
|
||||
setAssignedBand({
|
||||
patientId: data.patient_id,
|
||||
@@ -98,9 +92,8 @@ function App() {
|
||||
setStep('complete');
|
||||
setShowKeyboard(false);
|
||||
} catch (error) {
|
||||
console.error('Check-in failed:', error);
|
||||
setError(error.message);
|
||||
alert(`Failed to check in: ${error.message}\n\nMake sure the backend is running at ${API_BASE}`);
|
||||
alert(`Failed to check in: ${error.message}`);
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
@@ -147,7 +140,7 @@ function App() {
|
||||
|
||||
if (step === 'form') {
|
||||
return (
|
||||
<div className={`min-h-screen bg-gradient-to-br from-blue-50 to-blue-100 p-4 ${showKeyboard ? 'pb-96' : ''}`}>
|
||||
<div className={`min-h-screen bg-gradient-to-br from-blue-50 to-blue-100 p-4 transition-all ${showKeyboard ? 'pb-[450px]' : ''}`}>
|
||||
<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>
|
||||
@@ -171,8 +164,8 @@ function App() {
|
||||
type="text"
|
||||
value={formData.firstName}
|
||||
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"
|
||||
onChange={(e) => setFormData({...formData, firstName: e.target.value})}
|
||||
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"
|
||||
placeholder="Tap to type"
|
||||
/>
|
||||
</div>
|
||||
@@ -184,8 +177,8 @@ function App() {
|
||||
type="text"
|
||||
value={formData.lastName}
|
||||
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"
|
||||
onChange={(e) => setFormData({...formData, lastName: e.target.value})}
|
||||
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"
|
||||
placeholder="Tap to type"
|
||||
/>
|
||||
</div>
|
||||
@@ -272,71 +265,71 @@ function App() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* On-Screen Keyboard - ONLY ONE DECLARATION */}
|
||||
{/* react-simple-keyboard */}
|
||||
{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="fixed bottom-0 left-0 right-0 bg-white border-t-4 border-blue-500 shadow-2xl p-6 z-50">
|
||||
<div className="max-w-6xl 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">
|
||||
<div>
|
||||
<p className="text-sm text-gray-600">Currently typing:</p>
|
||||
<p className="font-bold text-2xl text-gray-800">
|
||||
{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>
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowKeyboard(false);
|
||||
setActiveField(null);
|
||||
}}
|
||||
className="bg-red-500 text-white px-6 py-3 rounded-lg text-xl font-bold hover:bg-red-600 active:scale-95"
|
||||
>
|
||||
✕ Close
|
||||
</button>
|
||||
</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 className="bg-gray-100 p-4 rounded-lg mb-4">
|
||||
<p className="text-gray-600 text-sm mb-1">Preview:</p>
|
||||
<p className="text-2xl font-mono font-bold text-gray-800">
|
||||
{formData[activeField] || '(empty)'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p className="text-center text-gray-400 text-sm mt-4">
|
||||
Tap any key to type • Tap ✓ Done when finished
|
||||
</p>
|
||||
|
||||
<Keyboard
|
||||
keyboardRef={r => (keyboard.current = r)}
|
||||
layoutName={layoutName}
|
||||
onChange={onKeyboardChange}
|
||||
onKeyPress={onKeyPress}
|
||||
theme="hg-theme-default hg-layout-default vitallink-keyboard"
|
||||
display={{
|
||||
'{bksp}': '⌫ backspace',
|
||||
'{enter}': 'enter',
|
||||
'{shift}': '⬆ shift',
|
||||
'{lock}': 'caps',
|
||||
'{tab}': 'tab',
|
||||
'{space}': 'space',
|
||||
'{close}': '✓ Done'
|
||||
}}
|
||||
buttonTheme={[
|
||||
{
|
||||
class: "hg-close-button",
|
||||
buttons: "{close}"
|
||||
}
|
||||
]}
|
||||
layout={{
|
||||
default: [
|
||||
"Q W E R T Y U I O P {bksp}",
|
||||
"A S D F G H J K L",
|
||||
"{shift} Z X C V B N M {shift}",
|
||||
"{space} {close}"
|
||||
],
|
||||
shift: [
|
||||
"Q W E R T Y U I O P {bksp}",
|
||||
"A S D F G H J K L",
|
||||
"{shift} Z X C V B N M {shift}",
|
||||
"{space} {close}"
|
||||
]
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user