Repository: vnexos/Sonaha_FE
Pull request #17: contact form, navbar , gioi thieu
Author: login: haidang71214
Created: 2025-03-06T10:40:41Z | Merged: 2025-03-06T12:24:54Z



Diff:
diff --git a/app/(dashboard)/(non-home)/gioi-thieu/page.tsx b/app/(dashboard)/(non-home)/gioi-thieu/page.tsx
new file mode 100644
index 0000000..78ff19c
--- /dev/null
+++ b/app/(dashboard)/(non-home)/gioi-thieu/page.tsx
@@ -0,0 +1,5 @@
+import GioiThieu from "@/components/modules/gioi-thieu";
+
+export default function layout() {
+  return <GioiThieu />;
+}
diff --git a/app/(dashboard)/(non-home)/layout.tsx b/app/(dashboard)/(non-home)/layout.tsx
new file mode 100644
index 0000000..585fecb
--- /dev/null
+++ b/app/(dashboard)/(non-home)/layout.tsx
@@ -0,0 +1,5 @@
+import { ReactNode } from "react";
+
+export default function layout({ children }: { children: ReactNode }) {
+  return <div className="m-24">{children}</div>;
+}
diff --git a/app/(dashboard)/layout.tsx b/app/(dashboard)/layout.tsx
index bb4a2da..d0b68bb 100644
--- a/app/(dashboard)/layout.tsx
+++ b/app/(dashboard)/layout.tsx
@@ -1,12 +1,14 @@
 import { ReactNode } from "react";
 
 import { Navbar } from "@/components/common/navbar";
+import Contact from "@/components/common/contactbt";
 
 export default function layout({ children }: { children: ReactNode }) {
   return (
     <div className="relative flex flex-col h-screen">
       <Navbar />
       <main className="flex-grow">{children}</main>
+      <Contact />
     </div>
   );
 }
diff --git a/app/providers.tsx b/app/providers.tsx
index 0025aa4..5e4a61c 100644
--- a/app/providers.tsx
+++ b/app/providers.tsx
@@ -37,7 +37,7 @@ export function Providers({ children, themeProps }: Readonly<ProvidersProps>) {
             <AuthProvider>{children}</AuthProvider>
           </Provider>
         </BackdropProvider>
-        <ToastProvider placement="top-right" />
+        <ToastProvider placement="bottom-right" />
       </NextThemesProvider>
     </HeroUIProvider>
   );
diff --git a/components/common/contactbt.tsx b/components/common/contactbt.tsx
new file mode 100644
index 0000000..7839a5d
--- /dev/null
+++ b/components/common/contactbt.tsx
@@ -0,0 +1,245 @@
+"use client";
+import { Image } from "@heroui/image";
+import {
+  Modal,
+  ModalBody,
+  ModalContent,
+  ModalFooter,
+  ModalHeader,
+} from "@heroui/modal";
+import { addToast } from "@heroui/toast";
+import { Icon } from "@iconify/react";
+import { useEffect, useState } from "react";
+
+import { useSendContactMutation } from "@/store/queries/contact";
+import { ContactData, ContactErrors, ContactFields } from "@/types";
+
+const Contact = () => {
+  const [scrollPosition, setScrollPosition] = useState(0);
+  const [isModalOpen, setIsModalOpen] = useState(false);
+  const [contactData, setcontactData] = useState<ContactData>({
+    email: "",
+    name: "",
+    phone: "",
+    content: "",
+  });
+  const [errors, setErrors] = useState<ContactErrors>({});
+
+  const [sendContact, { isLoading }] = useSendContactMutation();
+
+  useEffect(() => {
+    const handleScroll = () => {
+      setScrollPosition(window.scrollY);
+    };
+
+    window.addEventListener("scroll", handleScroll);
+
+    return () => window.removeEventListener("scroll", handleScroll);
+  }, []);
+
+  const validateForm = () => {
+    let isValid = true;
+    const newErrors: ContactErrors = {};
+
+    if (!contactData.name.trim()) {
+      newErrors.name = "Tên không được để trống";
+      isValid = false;
+    }
+
+    if (!contactData.email.trim()) {
+      newErrors.email = "Email không được để trống";
+      isValid = false;
+    } else if (
+      !/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(
+        contactData.email,
+      )
+    ) {
+      newErrors.email = "Email không hợp lệ";
+      isValid = false;
+    }
+
+    if (!contactData.phone.trim()) {
+      newErrors.phone = "Số điện thoại không được để trống";
+      isValid = false;
+    } else if (!/^\d{10,11}$/.test(contactData.phone)) {
+      newErrors.phone = "Số điện thoại phải là 10-11 số";
+      isValid = false;
+    }
+
+    if (!contactData.content.trim()) {
+      newErrors.content = "Nội dung không được để trống";
+      isValid = false;
+    } else if (contactData.content.length > 1000) {
+      newErrors.content = "Nội dung không được vượt quá 1000 ký tự";
+      isValid = false;
+    }
+
+    setErrors(newErrors);
+
+    return isValid;
+  };
+
+  const handleChange = (
+    e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
+  ) => {
+    const { name, value } = e.target;
+    const field = name as ContactFields;
+
+    setcontactData((prev) => ({ ...prev, [field]: value }));
+    setErrors((prev) => ({ ...prev, [field]: undefined }));
+  };
+
+  const openModal = () => setIsModalOpen(true);
+  const closeModal = () => {
+    setIsModalOpen(false);
+    setcontactData({
+      email: "",
+      name: "",
+      phone: "",
+      content: "",
+    });
+    setErrors({});
+  };
+
+  const handleSubmit = async (e: React.FormEvent) => {
+    e.preventDefault();
+    if (validateForm()) {
+      try {
+        await sendContact(contactData).unwrap();
+        addToast({
+          title: "Đăng kí nhận tin thành công",
+          description: "Chúng tôi sẽ sớm thông tin cho bạn",
+          color: "success",
+        });
+        closeModal();
+      } catch {}
+    }
+  };
+
+  return (
+    <div
+      className={`
+        fixed bottom-4 right-4 flex flex-col gap-4 z-50
+        transition-all duration-300 ease-in-out
+        ${scrollPosition > 0 ? " rounded-lg p-4" : ""}
+      `}
+    >
+      <a
+        aria-label="Liên hệ qua Zalo"
+        className="w-14 h-14 bg-blue-500 rounded-full flex items-center justify-center shadow-lg hover:bg-blue-600 transition-colors"
+        href="https://zalo.me/0987654321"
+        rel="noopener noreferrer"
+        target="_blank"
+      >
+        <Image
+          alt="Zalo Icon"
+          className="w-8 h-8 text-white rounded-full"
+          src="https://sonagift.vn/upload/photo/images-1730705270.png"
+        />
+      </a>
+
+      <a
+        aria-label="Liên hệ qua Facebook"
+        className="w-14 h-14 bg-blue-500 rounded-full flex items-center justify-center shadow-lg hover:bg-blue-600 transition-colors"
+        href="https://facebook.com/sonaha"
+        rel="noopener noreferrer"
+        target="_blank"
+      >
+        <Icon className="w-8 h-8 text-white" icon="ic:baseline-facebook" />
+      </a>
+
+      <button
+        aria-label="Liên hệ qua Gmail"
+        className="w-14 h-14 bg-blue-500 rounded-full flex items-center justify-center shadow-lg hover:bg-blue-600 transition-colors"
+        onClick={openModal}
+      >
+        <Icon className="w-8 h-8 text-white" icon="ic:baseline-mail" />
+      </button>
+
+      <Modal
+        className="max-w-md mx-auto p-2 bg-white shadow-lg border border-gray-300"
+        isOpen={isModalOpen}
+        onClose={closeModal}
+      >
+        <ModalContent>
+          <ModalHeader className="text-lg font-semibold text-gray-800 p-2">
+            Đăng ký nhận tin
+          </ModalHeader>
+          <ModalBody className="p-2 space-y-2">
+            <form className="space-y-2" onSubmit={handleSubmit}>
+              <div className="flex gap-2">
+                <div className="w-1/2">
+                  <input
+                    className="mt-1 block w-full p-2 border border-gray-300 rounded-none focus:ring-indigo-500 focus:border-indigo-500"
+                    id={ContactFields.name}
+                    name={ContactFields.name}
+                    placeholder="Nhập tên của bạn"
+                    type="text"
+                    value={contactData.name}
+                    onChange={handleChange}
+                  />
+                  {errors.name && (
+                    <p className="mt-1 text-sm text-red-500">{errors.name}</p>
+                  )}
+                </div>
+                <div className="w-1/2">
+                  <input
+                    className="mt-1 block w-full p-2 border border-gray-300 rounded-none focus:ring-indigo-500 focus:border-indigo-500"
+                    id={ContactFields.phone}
+                    name={ContactFields.phone}
+                    placeholder="Nhập số điện thoại (10-11 số)"
+                    type="tel"
+                    value={contactData.phone}
+                    onChange={handleChange}
+                  />
+                  {errors.phone && (
+                    <p className="mt-1 text-sm text-red-500">{errors.phone}</p>
+                  )}
+                </div>
+              </div>
+              <div>
+                <input
+                  className="mt-1 block w-full p-2 border border-gray-300 rounded-none focus:ring-indigo-500 focus:border-indigo-500"
+                  id={ContactFields.email}
+                  name={ContactFields.email}
+                  placeholder="Nhập email của bạn"
+                  type="email"
+                  value={contactData.email}
+                  onChange={handleChange}
+                />
+                {errors.email && (
+                  <p className="mt-1 text-sm text-red-500">{errors.email}</p>
+                )}
+              </div>
+              <div>
+                <textarea
+                  className="mt-1 block w-full p-2 border border-gray-300 rounded-none focus:ring-indigo-500 focus:border-indigo-500"
+                  id={ContactFields.content}
+                  name={ContactFields.content}
+                  placeholder="Nhập nội dung của bạn"
+                  rows={2}
+                  value={contactData.content}
+                  onChange={handleChange}
+                />
+                {errors.content && (
+                  <p className="mt-1 text-sm text-red-500">{errors.content}</p>
+                )}
+              </div>
+            </form>
+          </ModalBody>
+          <ModalFooter className="p-2 flex flex-col gap-2">
+            <button
+              className="w-full bg-black text-white p-2 rounded-none hover:bg-gray-800 disabled:bg-gray-500"
+              disabled={isLoading}
+              onClick={handleSubmit}
+            >
+              {isLoading ? "Đang gửi..." : "Gửi"}
+            </button>
+          </ModalFooter>
+        </ModalContent>
+      </Modal>
+    </div>
+  );
+};
+
+export default Contact;
diff --git a/components/modules/gioi-thieu/index.tsx b/components/modules/gioi-thieu/index.tsx
new file mode 100644
index 0000000..1ad044a
--- /dev/null
+++ b/components/modules/gioi-thieu/index.tsx
@@ -0,0 +1,137 @@
+export default function GioiThieu() {
+  return (
+    <div className="max-w-7xl   mx-auto p-6 bg-white rounded-lg">
+      <h1 className="text-3xl font-bold text-gray-800 text-center mb-6">
+        GIỚI THIỆU VỀ CÔNG TY CỔ PHẦN BẤT ĐỘNG SẢN SONAHA
+      </h1>
+
+      <section className="mb-8">
+        <h2 className="text-2xl font-semibold text-gray-700 mb-4">
+          1. Giới thiệu chung
+        </h2>
+        <p className="text-gray-600 leading-relaxed">
+          Công ty Cổ phần Bất động sản SONAHA là đơn vị tiềm năng trong lĩnh vực
+          phân phối và đầu tư bất động sản, kết nối khách hàng với những dự án
+          tiềm năng, đảm bảo giá trị gia tăng bền vững. Với đội ngũ chuyên gia
+          giàu kinh nghiệm, hệ thống đối tác uy tín và tầm nhìn chiến lược,
+          SONAHA cam kết mang đến các giải pháp bất động sản tối ưu, đáp ứng nhu
+          cầu an cư và đầu tư của khách hàng. Với phương châm “Kiến tạo thịnh
+          vượng, xây dựng tương lai“, SONAHA không chỉ đơn thuần là một đơn vị
+          phân phối mà còn là người bạn đồng hành cùng khách hàng trên hành
+          trình phát triển tài sản và nâng cao chất lượng cuộc sống.
+        </p>
+      </section>
+
+      <section className="mb-8">
+        <h2 className="text-2xl font-semibold text-gray-700 mb-4">
+          2. Tầm nhìn
+        </h2>
+        <p className="text-gray-600 leading-relaxed">
+          SONAHA hướng tới trở thành thương hiệu phân phối bất động sản uy tín
+          hàng đầu, kết nối khách hàng với những cơ hội đầu tư tiềm năng, góp
+          phần xây dựng một thị trường bất động sản minh bạch, chuyên nghiệp và
+          phát triển bền vững.
+        </p>
+      </section>
+
+      <section className="mb-8">
+        <h2 className="text-2xl font-semibold text-gray-700 mb-4">
+          3. Sứ mệnh
+        </h2>
+        <p className="text-gray-600 leading-relaxed">
+          Với sứ mệnh “Kiến tạo thịnh vượng, xây dựng tương lai“, SONAHA cam kết
+          mang đến những giải pháp phân phối bất động sản tối ưu, giúp khách
+          hàng sở hữu sản phẩm chất lượng cao và gia tăng giá trị đầu tư. Chúng
+          tôi không chỉ cung cấp bất động sản mà còn đồng hành, tư vấn và hỗ trợ
+          để khách hàng có những quyết định đầu tư đúng đắn, hiệu quả.
+        </p>
+      </section>
+
+      <section className="mb-8">
+        <h2 className="text-2xl font-semibold text-gray-700 mb-4">
+          4. Giá trị cốt lõi
+        </h2>
+        <div className="text-gray-600 leading-relaxed">
+          <p>
+            SONAHA xây dựng giá trị thương hiệu dựa trên nền tảng S.O.N.A.H.A:
+          </p>
+          <ul className="list-none mt-2">
+            <li className="flex items-center mb-2">
+              <span className="text-yellow-500 mr-2">🔹</span> S – Sáng tạo:
+              Liên tục đổi mới để mang đến giải pháp nhà ở và đầu tư tối ưu.
+            </li>
+            <li className="flex items-center mb-2">
+              <span className="text-yellow-500 mr-2">🔹</span> O – Ổn định: Xây
+              dựng giá trị bền vững, đảm bảo sự an tâm lâu dài cho khách hàng.
+            </li>
+            <li className="flex items-center mb-2">
+              <span className="text-yellow-500 mr-2">🔹</span> N – Nhiệt huyết:
+              Phục vụ khách hàng bằng tất cả sự tận tâm và trách nhiệm.
+            </li>
+            <li className="flex items-center mb-2">
+              <span className="text-yellow-500 mr-2">🔹</span> A – An cư: Kiến
+              tạo không gian sống lý tưởng, giúp khách hàng an tâm gắn bó.
+            </li>
+            <li className="flex items-center mb-2">
+              <span className="text-yellow-500 mr-2">🔹</span> H – Hiệu quả: Tối
+              ưu từng dự án để mang lại giá trị cao nhất.
+            </li>
+            <li className="flex items-center mb-2">
+              <span className="text-yellow-500 mr-2">🔹</span> A – Ân cần: Đồng
+              hành cùng khách hàng, đặt lợi ích của họ lên hàng đầu.
+            </li>
+          </ul>
+        </div>
+      </section>
+
+      <section className="mb-8">
+        <h2 className="text-2xl font-semibold text-gray-700 mb-4">
+          5. Lĩnh vực hoạt động
+        </h2>
+        <p className="text-gray-600 leading-relaxed">
+          SONAHA cung cấp các dịch vụ bất động sản chuyên nghiệp, bao gồm: Phân
+          phối dự án bất động sản: Nhà phố, căn hộ, đất nền, biệt thự, bất động
+          sản nghỉ dưỡng... Tư vấn đầu tư: Định hướng và đưa ra giải pháp tài
+          chính tối ưu cho khách hàng. Ký gửi - Môi giới bất động sản: Hỗ trợ
+          mua bán, cho thuê, chuyển nhượng bất động sản. Hỗ trợ pháp lý & tài
+          chính: Tư vấn pháp lý, hỗ trợ vay vốn ngân hàng.
+        </p>
+      </section>
+
+      <section className="mb-8">
+        <h2 className="text-2xl font-semibold text-gray-700 mb-4">
+          6. Cam kết của SONAHA
+        </h2>
+        <div className="text-gray-600 leading-relaxed">
+          <p>
+            Với triết lý “Kiến tạo thịnh vượng, xây dựng tương lai“, SONAHA cam
+            kết:
+          </p>
+          <ul className="list-none mt-2">
+            <li className="flex items-center mb-2">
+              <span className="text-green-500 mr-2">✅</span> Sản phẩm chất
+              lượng – Cung cấp bất động sản có giá trị cao, pháp lý minh bạch.
+            </li>
+            <li className="flex items-center mb-2">
+              <span className="text-green-500 mr-2">✅</span> Dịch vụ chuyên
+              nghiệp – Đội ngũ tư vấn tận tâm, hỗ trợ khách hàng từ A-Z.
+            </li>
+            <li className="flex items-center mb-2">
+              <span className="text-green-500 mr-2">✅</span> Giải pháp tối ưu –
+              Tối đa lợi nhuận, giảm thiểu rủi ro cho nhà đầu tư.
+            </li>
+            <li className="flex items-center mb-2">
+              <span className="text-green-500 mr-2">✅</span> Đồng hành dài lâu
+              – Luôn hỗ trợ khách hàng không chỉ trong giao dịch mà còn trên
+              hành trình phát triển tài sản.
+            </li>
+          </ul>
+          <p>
+            Với SONAHA, mỗi khoản đầu tư không chỉ là một giao dịch mà còn là sự
+            kiến tạo thịnh vượng và định hình tương lai.
+          </p>
+        </div>
+      </section>
+    </div>
+  );
+}
diff --git a/config/site.ts b/config/site.ts
index bcc0174..5ce3a7b 100644
--- a/config/site.ts
+++ b/config/site.ts
@@ -12,10 +12,6 @@ export const siteConfig = {
       label: "Giới thiệu",
       href: "/gioi-thieu",
     },
-    {
-      label: "Quyền lợi",
-      href: "/quyen-loi",
-    },
   ],
   links: {},
 };
diff --git a/constants/endpoints.ts b/constants/endpoints.ts
index c599321..a7d0ace 100644
--- a/constants/endpoints.ts
+++ b/constants/endpoints.ts
@@ -9,9 +9,14 @@ const authEndpoint = {
   DETAIL: `${API_PREFIX}/auth/detail`,
   CHECK_TOKEN: `${API_PREFIX}/auth/checkToken?token={token}`,
 };
+const contactEndpoint = {
+  SEND_CONTACT: `${API_PREFIX}/contact`,
+  GET_CONTACT: `${API_PREFIX}/contact`,
+  DELETE_CONTACT: `${API_PREFIX}/contact{id}`,
+};
 
 const provinceEndpoint = {
   GET_ALL_PROVINCE: `${API_PREFIX}/province`,
 };
 
-export { authEndpoint, propritiesEndpoint, provinceEndpoint };
+export { authEndpoint, contactEndpoint, propritiesEndpoint, provinceEndpoint };
diff --git a/store/queries/contact.ts b/store/queries/contact.ts
new file mode 100644
index 0000000..9081925
--- /dev/null
+++ b/store/queries/contact.ts
@@ -0,0 +1,33 @@
+import { baseApi } from "../base";
+
+import { contactEndpoint } from "@/constants/endpoints";
+
+export const contactApi = baseApi.injectEndpoints({
+  endpoints: (builder) => ({
+    getAllContact: builder.query<any, any>({
+      query: () => ({
+        url: contactEndpoint.GET_CONTACT,
+        method: "GET",
+      }),
+    }),
+    sendContact: builder.mutation<any, any>({
+      query: (params) => ({
+        url: contactEndpoint.SEND_CONTACT,
+        method: "POST",
+        body: params,
+      }),
+    }),
+    deleteContact: builder.mutation<any, any>({
+      query: (id) => ({
+        url: contactEndpoint.DELETE_CONTACT.replace("{id}", id),
+        method: "DELETE",
+      }),
+    }),
+  }),
+});
+
+export const {
+  useGetAllContactQuery,
+  useSendContactMutation,
+  useDeleteContactMutation,
+} = contactApi;
diff --git a/styles/globals.css b/styles/globals.css
index 6e7648e..70ce64a 100644
--- a/styles/globals.css
+++ b/styles/globals.css
@@ -23,3 +23,7 @@
 *::-webkit-scrollbar-button {
   display:none;
 }
+:root {
+  --font-sans: "Montserrat", sans-serif;
+  --font-mono: "Menlo", monospace;
+}
diff --git a/types/index.ts b/types/index.ts
index 03db82a..2c011a4 100644
--- a/types/index.ts
+++ b/types/index.ts
@@ -34,3 +34,25 @@ export type Province = {
   full_name_end: string;
   code_name: string;
 };
+// Định nghĩa enum cho các field của form (không cần gán giá trị cụ thể)
+export enum ContactFields {
+  email = "email",
+  name = "name",
+  phone = "phone",
+  content = "content",
+}
+
+// Định nghĩa type cho contact data và errors
+export type ContactData = {
+  email: string;
+  name: string;
+  phone: string;
+  content: string;
+};
+
+export type ContactErrors = {
+  email?: string;
+  name?: string;
+  phone?: string;
+  content?: string;
+};


Reviews:
user: login: haidang71214
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T11:48:52Z

Review comments:
diff_hunk: @@ -0,0 +1,250 @@
+"use client";
+import { Image } from "@heroui/image";
+import {
+  Modal,
+  ModalBody,
+  ModalContent,
+  ModalFooter,
+  ModalHeader,
+} from "@heroui/modal"; // Import từ HeroUI
+import { addToast } from "@heroui/toast";
+import { Icon } from "@iconify/react"; // Import Icon component từ Iconify
+import { useEffect, useState } from "react";
+
+import { useSendContactMutation } from "@/store/queries/contact";
+
+const Contact = () => {
+  const [scrollPosition, setScrollPosition] = useState(0);
+  const [isModalOpen, setIsModalOpen] = useState(false);
+  const [formData, setFormData] = useState({
path: components/common/contactbt.tsx
user: login: haidang71214
body: địt Ilung
created_at: 2025-03-06T11:43:45Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,250 @@
+"use client";
+import { Image } from "@heroui/image";
+import {
+  Modal,
+  ModalBody,
+  ModalContent,
+  ModalFooter,
+  ModalHeader,
+} from "@heroui/modal"; // Import từ HeroUI
+import { addToast } from "@heroui/toast";
+import { Icon } from "@iconify/react"; // Import Icon component từ Iconify
+import { useEffect, useState } from "react";
+
+import { useSendContactMutation } from "@/store/queries/contact";
+
+const Contact = () => {
+  const [scrollPosition, setScrollPosition] = useState(0);
+  const [isModalOpen, setIsModalOpen] = useState(false);
+  const [formData, setFormData] = useState({
+    email: "",
+    name: "",
+    phone: "",
+    content: "",
+  });
+  const [errors, setErrors] = useState({
+    email: "",
+    name: "",
+    phone: "",
+    content: "",
+  });
+
+  // Sử dụng mutation từ contactApi
+  const [sendContact, { isLoading }] = useSendContactMutation();
+
+  useEffect(() => {
+    const handleScroll = () => {
+      setScrollPosition(window.scrollY);
+    };
+
+    window.addEventListener("scroll", handleScroll);
+
+    return () => {
+      window.removeEventListener("scroll", handleScroll);
+    };
+  }, []);
+
+  const validateForm = () => {
+    let isValid = true;
+    const newErrors = { email: "", name: "", phone: "", content: "" };
path: components/common/contactbt.tsx
user: login: haidang71214
body: sấy xong nhét vô mấy cái form này ha
created_at: 2025-03-06T11:46:27Z
author_association: COLLABORATOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-03-06T12:21:25Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=vnexos_Sonaha_FE&pullRequest=17) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=vnexos_Sonaha_FE&pullRequest=17&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=vnexos_Sonaha_FE&pullRequest=17&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=vnexos_Sonaha_FE&pullRequest=17&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=vnexos_Sonaha_FE&pullRequest=17&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=vnexos_Sonaha_FE&pullRequest=17&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=vnexos_Sonaha_FE&pullRequest=17)


author_association: NONE