From 7ff1d056c6cc03de28b50c8ace4597d1af1b6cc1 Mon Sep 17 00:00:00 2001 From: liberty-rising Date: Tue, 16 Jan 2024 19:48:45 +0100 Subject: [PATCH] integrate prettier formatter for frontend --- .github/workflows/react-quality.yml | 21 +++ .pre-commit-config.yaml | 7 +- .vscode/settings.json | 18 +- frontend/.prettierrc | 0 frontend/package-lock.json | 16 ++ frontend/package.json | 1 + .../src/pages/dashboards/CreateDashboard.jsx | 44 ++--- frontend/src/pages/dashboards/Dashboard.jsx | 69 +++++--- .../src/pages/dashboards/DashboardTable.jsx | 67 +++++--- .../pages/dashboards/DashboardsMenuPage.jsx | 20 ++- frontend/src/pages/upload/UploadPage.jsx | 119 ++++++++----- frontend/src/pages/user/UserPage.jsx | 76 +++++--- .../pages/verify-email/VerifyEmailPage.jsx | 162 +++++++++--------- 13 files changed, 398 insertions(+), 222 deletions(-) create mode 100644 .github/workflows/react-quality.yml create mode 100644 frontend/.prettierrc diff --git a/.github/workflows/react-quality.yml b/.github/workflows/react-quality.yml new file mode 100644 index 0000000..28a0c38 --- /dev/null +++ b/.github/workflows/react-quality.yml @@ -0,0 +1,21 @@ +name: React Code Quality Check + +on: + pull_request: + paths: + - 'frontend/**' + +jobs: + python-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Node.js + uses: actions/setup-node@v1 + with: + node-version: '14' + - name: Install dependencies and run Prettier + run: | + cd frontend + npm install + npx prettier --check . diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6beca13..ea75e41 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,11 +12,16 @@ repos: - id: flake8 files: ^backend/ # Run flake8 only on files in the backend/ directory exclude: ^backend/alembic/versions/ # Exclude alembic migration files - - repo: https://github.com/pre-commit/mirrors-mypy rev: 'v1.7.1' # Use the latest version hooks: - id: mypy files: ^backend/ exclude: ^backend/alembic/versions/ # Exclude alembic migration files +- repo: https://github.com/pre-commit/mirrors-prettier + rev: 'v3.1.0' + hooks: + - id: prettier + files: ^frontend/ # Adjust this path to where your React code is + diff --git a/.vscode/settings.json b/.vscode/settings.json index 18342e8..1ed0b0d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,21 @@ "editor.formatOnSave": true, "files.trimTrailingWhitespace": true, }, - "workbench.editor.enablePreview": false + "workbench.editor.enablePreview": false, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[javascriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, } \ No newline at end of file diff --git a/frontend/.prettierrc b/frontend/.prettierrc new file mode 100644 index 0000000..e69de29 diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 065b0fd..5fc7290 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -32,6 +32,7 @@ "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.4", + "prettier": "^3.2.2", "vite": "^5.0.0" } }, @@ -4405,6 +4406,21 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.2.tgz", + "integrity": "sha512-HTByuKZzw7utPiDO523Tt2pLtEyK7OibUD9suEJQrPUCYQqrHr74GGX6VidMrovbf/I50mPqr8j/II6oBAuc5A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index ca4784f..5123018 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -34,6 +34,7 @@ "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.4", + "prettier": "^3.2.2", "vite": "^5.0.0" } } diff --git a/frontend/src/pages/dashboards/CreateDashboard.jsx b/frontend/src/pages/dashboards/CreateDashboard.jsx index 2783ac9..82338f6 100644 --- a/frontend/src/pages/dashboards/CreateDashboard.jsx +++ b/frontend/src/pages/dashboards/CreateDashboard.jsx @@ -1,40 +1,42 @@ -import React, { useState, useEffect } from 'react'; -import { Box, TextField, Button, Typography } from '@mui/material'; -import axios from 'axios'; -import { useNavigate } from 'react-router-dom'; -import { API_URL } from '../../utils/constants'; +import React, { useState, useEffect } from "react"; +import { Box, TextField, Button, Typography } from "@mui/material"; +import axios from "axios"; +import { useNavigate } from "react-router-dom"; +import { API_URL } from "../../utils/constants"; const CreateDashboardPage = () => { - const [organization, setOrganization] = useState(''); - const [name, setName] = useState(''); - const [description, setDescription] = useState(''); + const [organization, setOrganization] = useState(""); + const [name, setName] = useState(""); + const [description, setDescription] = useState(""); const navigate = useNavigate(); useEffect(() => { // Fetch organization - axios.get(`${API_URL}users/me/`) - .then(response => { + axios + .get(`${API_URL}users/me/`) + .then((response) => { setOrganization(response.data.organization); }) - .catch(error => console.error('Error fetching organization:', error)); + .catch((error) => console.error("Error fetching organization:", error)); }, []); const handleSubmit = (event) => { event.preventDefault(); - axios.post(`${API_URL}dashboard/`, { name, description, organization }) - .then(response => { + axios + .post(`${API_URL}dashboard/`, { name, description, organization }) + .then((response) => { // Handle successful dashboard creation - console.log('Dashboard created:', response.data); - navigate('/dashboards') + console.log("Dashboard created:", response.data); + navigate("/dashboards"); }) - .catch(error => { - console.error('Error creating dashboard:', error); + .catch((error) => { + console.error("Error creating dashboard:", error); }); }; const handleBack = () => { - navigate('/dashboards') - } + navigate("/dashboards"); + }; return ( @@ -44,7 +46,7 @@ const CreateDashboardPage = () => { fullWidth label="Name" value={name} - onChange={e => setName(e.target.value)} + onChange={(e) => setName(e.target.value)} margin="normal" /> { fullWidth label="Description" value={description} - onChange={e => setDescription(e.target.value)} + onChange={(e) => setDescription(e.target.value)} margin="normal" /> diff --git a/frontend/src/pages/upload/UploadPage.jsx b/frontend/src/pages/upload/UploadPage.jsx index bee2424..51bc539 100644 --- a/frontend/src/pages/upload/UploadPage.jsx +++ b/frontend/src/pages/upload/UploadPage.jsx @@ -1,38 +1,44 @@ -import React, { useState, useEffect } from 'react'; -import { Box, Button, Stack, Typography } from '@mui/material'; -import axios from 'axios'; -import FileTypeSelector from './FileTypeSelector'; -import EncodingSelector from './EncodingSelector'; -import DescriptionField from './DescriptionField'; -import NewTableSelector from './NewTableSelector'; -import FileUploader from './FileUploader'; -import AlertSnackbar from './AlertSnackbar'; -import { API_URL } from '../../utils/constants'; +import React, { useState, useEffect } from "react"; +import { Box, Button, Stack, Typography } from "@mui/material"; +import axios from "axios"; +import FileTypeSelector from "./FileTypeSelector"; +import EncodingSelector from "./EncodingSelector"; +import DescriptionField from "./DescriptionField"; +import NewTableSelector from "./NewTableSelector"; +import FileUploader from "./FileUploader"; +import AlertSnackbar from "./AlertSnackbar"; +import { API_URL } from "../../utils/constants"; function UploadPage() { const [fileTypes, setFileTypes] = useState([]); const [encodings, setEncodings] = useState([]); - const [fileType, setFileType] = useState(''); - const [encoding, setEncoding] = useState(''); - const [description, setDescription] = useState(''); - const [isNewTable, setIsNewTable] = useState('no'); + const [fileType, setFileType] = useState(""); + const [encoding, setEncoding] = useState(""); + const [description, setDescription] = useState(""); + const [isNewTable, setIsNewTable] = useState("no"); const [file, setFile] = useState(null); const [analyzed, setAnalyzed] = useState(false); - const [alertInfo, setAlertInfo] = useState({ open: false, message: '', severity: 'info' }); + const [alertInfo, setAlertInfo] = useState({ + open: false, + message: "", + severity: "info", + }); useEffect(() => { // Fetch file types - axios.get(`${API_URL}file_types/`) - .then(response => setFileTypes(response.data)) - .catch(error => console.error('Error fetching file types', error)); + axios + .get(`${API_URL}file_types/`) + .then((response) => setFileTypes(response.data)) + .catch((error) => console.error("Error fetching file types", error)); }, []); useEffect(() => { - if (fileType === 'csv') { + if (fileType === "csv") { // Fetch encodings - axios.get(`${API_URL}encodings/`, { params: { file_type: fileType } }) - .then(response => setEncodings(response.data)) - .catch(error => console.error('Error fetching encodings', error)); + axios + .get(`${API_URL}encodings/`, { params: { file_type: fileType } }) + .then((response) => setEncodings(response.data)) + .catch((error) => console.error("Error fetching encodings", error)); } }, [fileType]); @@ -43,40 +49,67 @@ function UploadPage() { const handleSubmit = async () => { const formData = new FormData(); - formData.append('file', file); - formData.append('extra_desc', description); - formData.append('is_new_table', isNewTable === 'yes'); - formData.append('encoding', encoding); + formData.append("file", file); + formData.append("extra_desc", description); + formData.append("is_new_table", isNewTable === "yes"); + formData.append("encoding", encoding); try { const response = await axios.post(`${API_URL}upload/`, formData); if (response.status === 200) { - setAlertInfo({ open: true, message: 'File uploaded successfully!', severity: 'success' }); + setAlertInfo({ + open: true, + message: "File uploaded successfully!", + severity: "success", + }); } else { - setAlertInfo({ open: true, message: `Failed to upload file: ${response.statusText}`, severity: 'error' }); + setAlertInfo({ + open: true, + message: `Failed to upload file: ${response.statusText}`, + severity: "error", + }); } } catch (error) { - setAlertInfo({ open: true, message: `An error occurred: ${error.message}`, severity: 'error' }); + setAlertInfo({ + open: true, + message: `An error occurred: ${error.message}`, + severity: "error", + }); } }; const handleCloseSnackbar = () => { setAlertInfo({ ...alertInfo, open: false }); }; - + return ( - - 📥 Data Upload + + + 📥 Data Upload + - - - {fileType === 'csv' && ( - + + + {fileType === "csv" && ( + )} - + @@ -101,14 +134,14 @@ function UploadPage() { - ); } -export default UploadPage +export default UploadPage; diff --git a/frontend/src/pages/user/UserPage.jsx b/frontend/src/pages/user/UserPage.jsx index dab0f49..87830c6 100644 --- a/frontend/src/pages/user/UserPage.jsx +++ b/frontend/src/pages/user/UserPage.jsx @@ -1,22 +1,22 @@ -import React, { useEffect, useState } from 'react'; -import axios from 'axios'; -import EmailIcon from '@mui/icons-material/Email'; -import BusinessIcon from '@mui/icons-material/Business'; -import AssignmentIndIcon from '@mui/icons-material/AssignmentInd'; -import AccountCircleIcon from '@mui/icons-material/AccountCircle'; -import { Alert, Box, CircularProgress, Grid, Typography } from '@mui/material'; -import InfoCard from './InfoCard'; -import ChangePassword from '../../components/change-password/ChangePassword'; -import { updateUserPassword } from '../../utils/updateUserPassword'; -import { API_URL } from '../../utils/constants'; +import React, { useEffect, useState } from "react"; +import axios from "axios"; +import EmailIcon from "@mui/icons-material/Email"; +import BusinessIcon from "@mui/icons-material/Business"; +import AssignmentIndIcon from "@mui/icons-material/AssignmentInd"; +import AccountCircleIcon from "@mui/icons-material/AccountCircle"; +import { Alert, Box, CircularProgress, Grid, Typography } from "@mui/material"; +import InfoCard from "./InfoCard"; +import ChangePassword from "../../components/change-password/ChangePassword"; +import { updateUserPassword } from "../../utils/updateUserPassword"; +import { API_URL } from "../../utils/constants"; const UserPage = () => { const [userData, setUserData] = useState(null); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [organizationData, setOrganizationData] = useState(null); - const [errorMessage, setErrorMessage] = useState(''); - const [successMessage, setSuccessMessage] = useState(''); + const [errorMessage, setErrorMessage] = useState(""); + const [successMessage, setSuccessMessage] = useState(""); useEffect(() => { setIsLoading(true); @@ -28,8 +28,8 @@ const UserPage = () => { // Fetch organization data if organization_id is present if (userData.organization_id) { - const orgResponse = await axios.get(`${API_URL}organization/`, { - params: { org_id: userData.organization_id } + const orgResponse = await axios.get(`${API_URL}organization/`, { + params: { org_id: userData.organization_id }, }); setOrganizationData(orgResponse.data); } @@ -43,14 +43,28 @@ const UserPage = () => { fetchData(); }, []); - const handleChangePassword = async (oldPassword, newPassword, confirmPassword) => { - return await updateUserPassword(oldPassword, newPassword, confirmPassword, setErrorMessage, setSuccessMessage); + const handleChangePassword = async ( + oldPassword, + newPassword, + confirmPassword, + ) => { + return await updateUserPassword( + oldPassword, + newPassword, + confirmPassword, + setErrorMessage, + setSuccessMessage, + ); }; return ( - - 👤 User Panel + + + 👤 User Panel + {isLoading ? ( @@ -59,16 +73,32 @@ const UserPage = () => { {error} ) : userData ? ( - + - - + + ) : ( User details not available. )} - + ); }; diff --git a/frontend/src/pages/verify-email/VerifyEmailPage.jsx b/frontend/src/pages/verify-email/VerifyEmailPage.jsx index 5557771..e1ef0cc 100644 --- a/frontend/src/pages/verify-email/VerifyEmailPage.jsx +++ b/frontend/src/pages/verify-email/VerifyEmailPage.jsx @@ -1,87 +1,95 @@ -import React, { useState, useEffect } from 'react'; -import { useLocation, useNavigate } from 'react-router-dom'; -import { Box, Button, Container, Typography } from '@mui/material'; -import { useAuth } from '../../contexts/AuthContext'; -import { API_URL } from '../../utils/constants'; -import axios from 'axios'; -import { set } from 'date-fns'; +import React, { useState, useEffect } from "react"; +import { useLocation, useNavigate } from "react-router-dom"; +import { Box, Button, Container, Typography } from "@mui/material"; +import { useAuth } from "../../contexts/AuthContext"; +import { API_URL } from "../../utils/constants"; +import axios from "axios"; const VerifyEmailPage = () => { - const location = useLocation(); - const navigate = useNavigate(); - const email = location.state?.email || null; - const [token, setToken] = useState(null); - const { updateAuth, updateEmailVerification } = useAuth(); + const location = useLocation(); + const navigate = useNavigate(); + const email = location.state?.email || null; + const [token, setToken] = useState(null); + const { updateAuth, updateEmailVerification } = useAuth(); - useEffect(() => { - const params = new URLSearchParams(location.search); - const token = params.get('token'); - setToken(token); - }, [location]); + useEffect(() => { + const params = new URLSearchParams(location.search); + const token = params.get("token"); + setToken(token); + }, [location]); - useEffect(() => { - if (token) { - console.log("token", token) - axios.put(`${API_URL}users/verify-email/`, { token }) - .then(response => { - // Handle successful verification - updateEmailVerification(true); - - axios.get(`${API_URL}verify-token/`) - .then(response => { - // Handle successful token verification - updateAuth(true); - console.log('Token verified successfully'); - navigate('/dashboards'); - }) - .catch(error => { - // Handle failed token verification - console.log('Failed to verify token'); - navigate('/login', { state: { emailVerified: true } }); - }); - }) - .catch(error => { - // Handle failed verification - navigate('/login'); - }); - } - }, [token, navigate, updateEmailVerification]); + useEffect(() => { + if (token) { + console.log("token", token); + axios + .put(`${API_URL}users/verify-email/`, { token }) + .then((response) => { + // Handle successful verification + updateEmailVerification(true); - const handleResendEmail = async (event) => { - event.preventDefault(); - axios.post(`${API_URL}users/send-verification-email/`, { email }) - .then(response => { - // Handle successful email resend - console.log('Verification email sent successfully'); + axios + .get(`${API_URL}verify-token/`) + .then((response) => { + // Handle successful token verification + updateAuth(true); + console.log("Token verified successfully"); + navigate("/dashboards"); }) - .catch(error => { - // Handle failed email resend - console.log('Failed to send verification email'); + .catch((error) => { + // Handle failed token verification + console.log("Failed to verify token"); + navigate("/login", { state: { emailVerified: true } }); }); - }; + }) + .catch((error) => { + // Handle failed verification + navigate("/login"); + }); + } + }, [token, navigate, updateEmailVerification]); - return ( - - - - Verify Your Email - - - We've sent a verification link to your email address. Please check your inbox and click the link to verify your email. - - - - - ); + const handleResendEmail = async (event) => { + event.preventDefault(); + axios + .post(`${API_URL}users/send-verification-email/`, { email }) + .then((response) => { + // Handle successful email resend + console.log("Verification email sent successfully"); + }) + .catch((error) => { + // Handle failed email resend + console.log("Failed to send verification email"); + }); + }; + + return ( + + + + Verify Your Email + + + We've sent a verification link to your email address. Please check + your inbox and click the link to verify your email. + + + + + ); }; -export default VerifyEmailPage; \ No newline at end of file +export default VerifyEmailPage;