File size: 11,239 Bytes
49d3082
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
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;