Spaces:
Sleeping
Sleeping
import { useEffect, useState } from "react"; | |
import { useAtom } from "jotai"; | |
import { VoiceAssistAtom, CurrentRollAtom, CurrentGRNAtom, TranscribeAtom, rollsAtom, grnsAtom, searchAtom } from "./Variables"; | |
import { Routes, Route, useNavigate } from "react-router-dom"; | |
import { CusNavbar } from "./Components/CusNavbar"; | |
import RollCard from "./Components/RollCard"; | |
import HomePage from "./Pages/HomePage"; | |
import ErrorPage from "./Pages/ErrorPage"; | |
import AddRollPage from "./Pages/AddRollPage"; | |
import TranscribePage from "./Pages/TranscribePage"; | |
import RollDetailPage from "./Pages/RollDetailPage"; | |
import GRNCard from "./Components/GRNCard"; | |
import GRNDetailPage from "./Pages/GRNDetailPage"; | |
function App() { | |
const [search, setSearch] = useAtom(searchAtom); | |
const [rolls, setRolls] = useAtom(rollsAtom); | |
const [grns, setGrns] = useAtom(grnsAtom); | |
const [voiceAssist, setVoiceAssist] = useAtom(VoiceAssistAtom); | |
const [currentRoll, setCurrentRoll] = useAtom(CurrentRollAtom); | |
const [currentGRN, setCurrentGRN] = useAtom(CurrentGRNAtom); | |
const [transcribe, setTranscribe] = useAtom(TranscribeAtom); | |
const [sidebar, setSidebar] = useState(true); | |
const navigate = useNavigate(); | |
useEffect(() => { | |
if (localStorage.getItem("currentGRN")) { | |
setCurrentGRN(JSON.parse(localStorage.getItem("currentGRN"))); | |
} | |
fetch("/api/grns") | |
.then((res) => res.json()) | |
.then((data) => { | |
setGrns(data["data"]); | |
voiceAssist.on(["open *", "grn *", "open grn *"], true).then((i, wildcard) => { | |
wildcard = wildcard.replace(/\s/g, "").replace(/-/g, ""); | |
let found = false; | |
for (let index = 0; index < data["data"].length; index++) { | |
if (data["data"][index].GRN.toLowerCase() == wildcard.toLowerCase()) { | |
setCurrentGRN(data["data"][index]); | |
localStorage.setItem("currentGRN", JSON.stringify(data["data"][index])); | |
setTranscribe((prev) => [...prev.slice(0, -1), { msg: "open GRN " + wildcard, isCommand: true }]); | |
navigate("/grn"); | |
found = true; | |
} | |
} | |
if (!found) { | |
voiceAssist.say("No GRN found with that Number"); | |
} | |
}); | |
}) | |
.catch((err) => console.error(err)); | |
voiceAssist.emptyCommands(); | |
voiceAssist.on(["search *"], true).then((i, wildcard) => { | |
wildcard = wildcard.replace(/ /g, ""); | |
setSearch(wildcard); | |
setTranscribe((prev) => [...prev.slice(0, -1), { msg: "search " + wildcard, isCommand: true }]); | |
}); | |
voiceAssist.on(["transcribe"]).then((i) => { | |
setTranscribe((prev) => [...prev.slice(0, -1), { msg: "transcribe", isCommand: true }]); | |
navigate("/transcribe"); | |
}); | |
voiceAssist.on(["home", "go to home"]).then((i) => { | |
setTranscribe((prev) => [...prev.slice(0, -1), { msg: "home", isCommand: true }]); | |
navigate("/"); | |
}); | |
voiceAssist.on(["refresh"]).then((i) => { | |
window.location.reload(); | |
}); | |
voiceAssist.fatality(); | |
setTimeout(() => { | |
voiceAssist | |
.initialize({ | |
lang: "en-US", | |
continuous: true, | |
soundex: true, | |
debug: true, | |
executionKeyword: "and do it now", | |
listen: true, | |
name: "", | |
speed: 1.2, | |
// mode:"quick" | |
}) | |
.then(() => { | |
console.log("Artyom has been succesfully initialized"); | |
}) | |
.catch((err) => { | |
console.error("Artyom couldn't be initialized: ", err); | |
}); | |
}, 250); | |
voiceAssist.redirectRecognizedTextOutput((recognized, isFinal) => { | |
if (isFinal && recognized != "") { | |
setTranscribe((prev) => [...prev, { msg: recognized, isCommand: false }]); | |
} | |
}); | |
}, []); | |
return ( | |
<div className="flex flex-col h-screen w-full overflow-hidden relative"> | |
{transcribe.length > 0 && ( | |
<div className="z-50 max-w-[25%] absolute bottom-5 right-10 flex flex-col items-end gap-2"> | |
{transcribe.map((item, index) => { | |
if (transcribe.length - index > 4) return null; | |
return ( | |
<div key={index} className={"relative w-fit max-w-full text-white rounded-lg rounded-br-none p-3 px-4 transition-all duration-700 origin-bottom-right " + (item?.isCommand ? "bg-orange-500 " : "bg-primary-500 ")} style={{ opacity: transcribe.length - index < 4 ? 1.25 - (transcribe.length - index) * 0.25 : 0, transform: transcribe.length - index == 4 ? "translate(200px,0px)" : "scale(1)" }}> | |
<p>{item?.msg}</p> | |
<svg className={"absolute translate-x-1/2 translate-y-[2.5px] bottom-0 right-0 h-5 w-5 scale-x-150 " + (item?.isCommand ? "text-orange-500" : "text-primary-500")} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path fill="currentColor" d="M21 21H3l9-18Z" /> | |
</svg> | |
</div> | |
); | |
})} | |
</div> | |
)} | |
<CusNavbar /> | |
<div className="flex flex-row w-full h-[calc(100vh-4rem)] flex-nowrap items-center justify-between border-t border-primary-950"> | |
<div className={"border-r border-primary-950 h-full p-5 relative px-0 transition-all " + (sidebar ? "w-[20%] min-w-64" : "w-0 ")}> | |
<svg | |
onClick={() => { | |
setSidebar(!sidebar); | |
}} | |
className={"absolute top-0 w-10 h-10 p-2 z-50 border border-t-0 border-primary-950 hover:bg-primary-100 cursor-pointer transition-all " + (sidebar ? "border-l-0 right-0 -scale-x-100" : "border-l-0 -right-10")} | |
viewBox="-0.2 0 1 1" | |
xmlns="http://www.w3.org/2000/svg" | |
> | |
<path d="m0.138 0.023 0.434 0.417 0.004 0.003c0.015 0.014 0.023 0.033 0.024 0.055l0 0.007c-0.001 0.02 -0.01 0.038 -0.027 0.054l0 0L0.138 0.977a0.082 0.082 0 0 1 -0.114 0 0.079 0.079 0 0 1 0 -0.114l0.376 -0.361L0.024 0.137a0.079 0.079 0 0 1 0 -0.114 0.082 0.082 0 0 1 0.114 0" fill="#1C1C1F" /> | |
</svg> | |
<div className={"flex flex-col w-full h-full gap-3 transition-all origin-left " + (sidebar ? "" : "scale-x-0")}> | |
<div className="relative w-[calc(100%-2.5rem)] mx-auto h-10"> | |
<div className="grid place-items-center absolute text-blue-gray-500 top-2/4 right-12 -translate-y-2/4 w-5 h-5"> | |
<svg width={16} height={16} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path fill="currentColor" d="M21.71 20.29 18 16.61A9 9 0 1 0 16.61 18l3.68 3.68a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.39M11 18a7 7 0 1 1 7-7 7 7 0 0 1-7 7" /> | |
</svg> | |
</div> | |
<input | |
onChange={(event) => { | |
setSearch(event.target.value); | |
}} | |
value={search} | |
className="peer w-[calc(100%-2.5rem)] h-full bg-transparent text-blue-gray-700 font-sans font-normal outline outline-0 focus:outline-0 disabled:bg-blue-gray-50 disabled:border-0 disabled:cursor-not-allowed transition-all placeholder-shown:border placeholder-shown:border-blue-gray-200 placeholder-shown:border-t-blue-gray-200 border focus:border-2 border-t-transparent focus:border-t-transparent placeholder:opacity-0 focus:placeholder:opacity-100 text-sm px-3 py-2.5 rounded-[7px] !pr-9 border-blue-gray-200 focus:border-gray-900" | |
placeholder=" " | |
/> | |
<label className="flex w-[calc(100%-2.5rem)] h-full select-none pointer-events-none absolute left-0 font-normal !overflow-visible truncate peer-placeholder-shown:text-blue-gray-500 leading-tight peer-focus:leading-tight peer-disabled:text-transparent peer-disabled:peer-placeholder-shown:text-blue-gray-500 transition-all -top-1.5 peer-placeholder-shown:text-sm text-[11px] peer-focus:text-[11px] before:content[' '] before:block before:box-border before:w-2.5 before:h-1.5 before:mt-[6.5px] before:mr-1 peer-placeholder-shown:before:border-transparent before:rounded-tl-md before:border-t peer-focus:before:border-t-2 before:border-l peer-focus:before:border-l-2 before:pointer-events-none before:transition-all peer-disabled:before:border-transparent after:content[' '] after:block after:flex-grow after:box-border after:w-2.5 after:h-1.5 after:mt-[6.5px] after:ml-1 peer-placeholder-shown:after:border-transparent after:rounded-tr-md after:border-t peer-focus:after:border-t-2 after:border-r peer-focus:after:border-r-2 after:pointer-events-none after:transition-all peer-disabled:after:border-transparent peer-placeholder-shown:leading-[3.75] text-gray-500 peer-focus:text-gray-900 before:border-blue-gray-200 peer-focus:before:!border-gray-900 after:border-blue-gray-200 peer-focus:after:!border-gray-900">Search Roll No. </label> | |
</div> | |
<div className="w-full h-full flex flex-col gap-2 text-primary-700 overflow-y-scroll pl-6 py-5 px-5 noScrollBars"> | |
{grns.map((grn, index) => { | |
if (search && !grn.supplierName.toLowerCase().includes(search.toLowerCase()) && !grn.buyer.toLowerCase().includes(search.toLowerCase()) && !grn.GRN.toLowerCase().includes(search.toLowerCase())) return null; | |
return <GRNCard key={index} GRN={grn} />; | |
})} | |
</div> | |
</div> | |
</div> | |
<div className={"border-r h-full overflow-y-auto custom-scrollbar " + (sidebar ? "w-[80%]" : "w-full")}> | |
<Routes> | |
<Route path="/" element={<HomePage />} /> | |
{/* <Route path="/add-roll" element={<AddRollPage />} /> */} | |
<Route path="/roll" element={<RollDetailPage />} /> | |
<Route path="/grn" element={<GRNDetailPage sidebar={sidebar} />} /> | |
<Route path="/transcribe" element={<TranscribePage />} /> | |
<Route path="*" element={<ErrorPage />} /> | |
</Routes> | |
</div> | |
</div> | |
</div> | |
); | |
} | |
export default App; | |