Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/mqtt check connection #209

Merged
merged 10 commits into from
Nov 27, 2023
123 changes: 112 additions & 11 deletions app/routes/account.mydevices.$boxId.edit.mqtt.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/node";
import { redirect } from "@remix-run/node";
import { Form } from "@remix-run/react";
import { json, redirect } from "@remix-run/node";
import { Form, useActionData } from "@remix-run/react";
import { getUserId } from "~/session.server";
import { Save } from "lucide-react";
import { Checkbox } from "@/components/ui/checkbox";
import { useState } from "react";
import React, { useState } from "react";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Label } from "@/components/ui/label";
import ErrorMessage from "~/components/error-message";

import * as mqtt from "mqtt/dist/mqtt.min";
import { toast } from "~/components/ui/use-toast";
YouQam marked this conversation as resolved.
Show resolved Hide resolved

//*****************************************************
export async function loader({ request, params }: LoaderFunctionArgs) {
//* if user is not logged in, redirect to home
Expand All @@ -20,12 +23,87 @@ export async function loader({ request, params }: LoaderFunctionArgs) {

//*****************************************************
export async function action({ request, params }: ActionFunctionArgs) {
return "";
console.log("actions");

const formData = await request.formData();
const { enableMQTTcb, mqqtURL, mqqtTopic } = Object.fromEntries(formData);
YouQam marked this conversation as resolved.
Show resolved Hide resolved

//* ToDo: if mqtt checkbox is not enabled, reset mqtt to default
if (!enableMQTTcb) {
return json({
errors: {
mqqtURL: null,
mqqtTopic: null,
reset: true,
},
mqttURL: mqqtURL,
status: 200,
});
}

const errors = {
mqqtURL: mqqtURL ? null : "Invalid URL (please use ws or wss URL)",
mqqtTopic: mqqtTopic ? null : "Invalid mqqt topic",
reset: false,
};

return json({
errors,
mqttURL: mqqtURL,
status: 200,
});
}

//**********************************
export default function EditBoxMQTT() {
const [mqttVal, setMqttVal] = useState(false);
const [mqttEnabled, setMqttEnabled] = useState(false);
const [mqttValid, setMqttValid] = useState(true);
const actionData = useActionData<typeof action>();

const mqqtURLRef = React.useRef<HTMLInputElement>(null);
const mqqtTopicRef = React.useRef<HTMLInputElement>(null);

React.useEffect(() => {
if (actionData) {
const hasErrors = Object.values(actionData?.errors).some(
(errorMessage) => errorMessage,
);

// ToDo
if (actionData.errors.reset) {
// Do nothing for now
} else if (!hasErrors) {
let isValidURL = false;

//* check mqtt url connection
mqtt
.connectAsync(actionData.mqttURL.toString())
// .connectAsync("wss://broker.emqx.io:8084/mqtt")
.then((e) => {
isValidURL = true;
});

setTimeout(() => {
if (isValidURL) {
console.log("🚀 MQTT URL is valid");
setMqttValid(true);
//* if qmtt url is valid, show conn. success msg
toast({
description: "Successfully connected to mqtt url!",
});
} else {
console.log("🚀 MQTT URL is not valid");
setMqttValid(false);
mqqtURLRef.current?.focus();
}
}, 1000);
} else if (hasErrors && actionData?.errors?.mqqtURL) {
mqqtURLRef.current?.focus();
} else if (hasErrors && actionData?.errors?.mqqtTopic) {
mqqtTopicRef.current?.focus();
}
}
}, [actionData]);

return (
<div className="grid grid-rows-1">
Expand All @@ -43,6 +121,7 @@ export default function EditBoxMQTT() {
<div>
{/* Save button */}
<button
type="submit"
name="intent"
value="save"
className=" h-12 w-12 rounded-full border-[1.5px] border-[#9b9494] hover:bg-[#e7e6e6]"
Expand Down Expand Up @@ -79,7 +158,10 @@ export default function EditBoxMQTT() {
</div>

<div className="my-6 flex items-center space-x-2">
<Checkbox onCheckedChange={() => setMqttVal(!mqttVal)} />
<Checkbox
name="enableMQTTcb"
onCheckedChange={() => setMqttEnabled(!mqttEnabled)}
/>
<label
htmlFor="terms"
className="cursor-pointer text-base font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
Expand All @@ -104,9 +186,22 @@ export default function EditBoxMQTT() {
autoFocus={true}
name="mqqtURL"
type="text"
ref={mqqtURLRef}
className="w-full rounded border border-gray-200 px-2 py-1 text-base disabled:cursor-not-allowed disabled:bg-[#eee]"
disabled={!mqttVal}
disabled={!mqttEnabled}
/>
{actionData?.errors?.mqqtURL && (
<div className="pt-1 text-[#FF0000]" id="mqqtURL-error">
{actionData.errors.mqqtURL}
</div>
)}

{!mqttValid && (
<div className="pt-1 text-[#FF0000]" id="mqqtURL-error">
Entered mqtt url is not valid, please try again with a valid
one.
</div>
)}
</div>
</div>

Expand All @@ -126,8 +221,15 @@ export default function EditBoxMQTT() {
autoFocus={true}
name="mqqtTopic"
type="text"
ref={mqqtTopicRef}
className="w-full rounded border border-gray-200 px-2 py-1 text-base disabled:cursor-not-allowed disabled:bg-[#eee]"
disabled={!mqttEnabled}
/>
{actionData?.errors?.mqqtTopic && (
<div className="pt-1 text-[#FF0000]" id="mqqtTopic-error">
{actionData.errors.mqqtTopic}
</div>
)}
</div>
</div>

Expand All @@ -142,7 +244,7 @@ export default function EditBoxMQTT() {
<div className="mt-1">
<RadioGroup
defaultValue="json"
disabled={!mqttVal}
disabled={!mqttEnabled}
className="disabled:cursor-not-allowed"
>
<div className="flex items-center space-x-2">
Expand Down Expand Up @@ -173,7 +275,7 @@ export default function EditBoxMQTT() {
name="mqqtDecode"
type="text"
className="w-full rounded border border-gray-200 px-2 py-1 text-base disabled:cursor-not-allowed disabled:bg-[#eee]"
disabled={!mqttVal}
disabled={!mqttEnabled}
/>
</div>
</div>
Expand All @@ -193,7 +295,7 @@ export default function EditBoxMQTT() {
name="mqqtConn"
type="text"
className="w-full rounded border border-gray-200 px-2 py-1 text-base disabled:cursor-not-allowed disabled:bg-[#eee]"
disabled={!mqttVal}
disabled={!mqttEnabled}
/>
</div>
</div>
Expand All @@ -211,4 +313,3 @@ export function ErrorBoundary() {
</div>
);
}

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
"lucide-react": "^0.263.1",
"mapbox-gl": "^2.14.1",
"morgan": "^1.10.0",
"mqtt": "^5.1.2",
"node-fetch": "^3.3.1",
"postcss-import": "^15.1.0",
"prom-client": "^15.0.0",
Expand Down