Source: pages-sections/Profile-Sections/UserInfo.js

import React, { useState, useEffect } from "react";
import { useRouter } from "next/router";
import classNames from "classnames";
import { makeStyles } from "@material-ui/core/styles";
import InputAdornment from "@material-ui/core/InputAdornment";
import People from "@material-ui/icons/People";
import Icon from "@material-ui/core/Icon";
import Button from "/components/CustomButtons/Button.js";
import Card from "/components/Card/Card.js";
import CardBody from "/components/Card/CardBody.js";
import CardFooter from "/components/Card/CardFooter.js";
import CustomInput from "/components/CustomInput/CustomInput.js";
import { useAuth } from "../../context/AuthContext";
import styles from "/styles/jss/nextjs-material-kit/pages/profilePage.js";
import { FormControl, Select, MenuItem, InputLabel } from "@material-ui/core";
import { getDatabase, ref, onValue, set } from "firebase/database";
import {
  AccountCircle,
  LocationOn,
  FitnessCenter,
  Height,
  SettingsApplications,
  Person,
  Wc,
} from "@material-ui/icons";

const useStyles = makeStyles(styles);
const useStyly = makeStyles({
  card: {
    marginTop: "10px",
  },
  cardBody: {
    marginTop: "10px",
  },
  inputIconsColor: {
    color: "#9c27b0",
  },
  button: {
    "&:hover": {
      backgroundColor: "primary",
    },
  },
  formContainer: {
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
    marginTop: "15px",
  },
  container: {
    display: "flex",
    justifyContent: "space-between",
    alignItems: "center",
  },
  data: {
    textAlign: "center",
    paddingRight: "5%",
    flex: "1",
  },
  cardFooterEdit: {
    display: "flex",
    justifyContent: "space-between",
  },
  cardFooterInfo: {
    display: "flex",
    justifyContent: "flex-end",
  },
});

/**
 * The `handleSubmit` function handles the form submission when the user updates their information.
 * It checks if the height and weight are valid numbers and within a certain range. If the values are
 * not valid, an alert is shown, and the form is reset to the original values. If the values are valid,
 * the data object is constructed with the new values, and the user's data is updated in the Firebase
 * Realtime Database. An alert is shown upon successful update, and the edit mode is disabled.
 * @param event - The form submission event
 * @returns If the height or weight is not valid, an alert is shown, and the form is reset to the original
 * values. If the height and weight are valid, the user's data is updated in the Firebase Realtime Database,
 * and an alert is shown upon successful update. The edit mode is then disabled.
 */
export const handleSubmit = (event) => {
  event.preventDefault();

  // Check if height and weight are valid numbers
  const isValidHeight =
    height === "" ||
    (!isNaN(parseFloat(height)) &&
      isFinite(height) &&
      height > 0 &&
      height <= 300);
  const isValidWeight =
    weight === "" ||
    (!isNaN(parseFloat(weight)) &&
      isFinite(weight) &&
      weight > 0 &&
      weight <= 200);

  // If height or weight is not valid, show an alert and reset to original values
  if (!isValidHeight || !isValidWeight) {
    alert("Please enter valid values for height and weight.");
    setLocation(originalLocation);
    setAtheleteType(originalAthleteType);
    setHeight(originalHeight);
    setWeight(originalWeight);
    setGender(originalGender);
    return;
  }

  // Construct the data object with the new values
  const newData = {
    gender,
    location,
    athleteType,
    height,
    weight,
  };

  // Get a reference to the Firebase Realtime Database
  const db = getDatabase();
  // Construct the path to the user's data in the database
  const userRef = ref(db, `users/${currentUser.uid}`);

  // Update user's data in the database
  set(userRef, newData)
    .then(() => {
      alert("Data updated successfully!");
      setIsEditMode(false); // Disable edit mode after submission
    })
    .catch((error) => {
      alert("Error updating data: ", error);
      // Handle error
    });
};

/**
 * The `handleEdit` function enables the edit mode when the user clicks the "Edit" button.
 * The user can then edit their information.
 */
export const handleEdit = () => {
  setIsEditMode(true);
};

/**
 * The `handleCancel` function cancels the changes made by the user and resets the form to the original
 * values.
 */
export const handleCancel = () => {
  setIsEditMode(false);
  // Reset to original values
  setLocation(originalLocation);
  setAtheleteType(originalAthleteType);
  setHeight(originalHeight);
  setWeight(originalWeight);
  setGender(originalGender);
};

/**
 * The `UserInfo` function in JavaScript handles user information display and edit functionality
 * with validation and error handling.
 * @returns The `UserInfo` component is returning a Card component containing user information such as
 * location, athlete type, height, and weight. If the user has not entered their information, the fields
 * will be empty. If the user has entered their information, the fields will be displayed. The user can
 * edit their information by clicking the "Edit" button. The user can then save or cancel the changes.
 * If the user saves the changes, the data is updated in the Firebase Realtime Database.
 * If the user cancels the changes, the form is reset to the original values.
 * If the user has not entered valid values for height and weight, an alert is shown.
 * If the user has entered valid values, the data is updated in the Firebase Realtime Database.
 * An alert is shown upon successful update, and the edit mode is disabled.
 * The user can also cancel the changes, and the form is reset to the original values.
 */

export function UserInfo() {
  const classes = useStyles();
  const classess = useStyly();
  const { currentUser } = useAuth();
  const router = useRouter();
  const [location, setLocation] = useState("");
  const [originalLocation, setOriginalLocation] = useState("");
  const [athleteType, setAtheleteType] = useState("");
  const [originalAthleteType, setOriginalAthleteType] = useState("");
  const [height, setHeight] = useState("");
  const [originalHeight, setOriginalHeight] = useState("");
  const [weight, setWeight] = useState("");
  const [originalWeight, setOriginalWeight] = useState("");
  const [gender, setGender] = useState("");
  const [originalGender, setOriginalGender] = useState("");
  const [isEditMode, setIsEditMode] = useState(false);

  // Fetch user data from Firebase when component mounts
  useEffect(() => {
    if (currentUser) {
      // Get a reference to the Firebase Realtime Database
      const db = getDatabase();
      // Construct the path to the user's data in the database
      const userRef = ref(db, `users/${currentUser.uid}`);
      // Fetch user's data from the database
      onValue(userRef, (snapshot) => {
        const userData = snapshot.val(); // Retrieve the user's data
        if (userData) {
          // If user data exists, update the state with the name
          setGender(userData.gender);
          setOriginalGender(userData.gender);
          setLocation(userData.location);
          setOriginalLocation(userData.location);
          setAtheleteType(userData.athleteType);
          setOriginalAthleteType(userData.athleteType);
          setHeight(userData.height);
          setOriginalHeight(userData.height);
          setWeight(userData.weight);
          setOriginalWeight(userData.weight);
        }
      });
    }
  }, [currentUser]);

  return (
    <Card className={classess.card}>
      <form className={classes.form} onSubmit={handleSubmit}>
        {!isEditMode ? (
          <div>
            {/* display mode */}
            <CardBody className={classess.cardBody}>
              <div className={classess.container}>
                <h5>Biological Gender: </h5>
                <h5 className={gender === "" ? classess.data : ""}>
                  {gender === "" ? "" : gender}
                </h5>
              </div>
              <div className={classess.container}>
                <h5>Location: </h5>
                <h5 className={location === "" ? classess.data : ""}>
                  {location === "" ? "" : location}
                </h5>
              </div>
              <div className={classess.container}>
                <h5>Athelete Type: </h5>
                <h5 className={athleteType === "" ? classess.data : ""}>
                  {athleteType === "" ? "" : athleteType}
                </h5>
              </div>
              <div className={classess.container}>
                <h5>Height (cm): </h5>
                <h5 className={height === "" ? classess.data : ""}>
                  {height === "" ? "" : height}
                </h5>
              </div>
              <div className={classess.container}>
                <h5>Weight (kg): </h5>
                <h5 className={weight === "" ? classess.data : ""}>
                  {weight === "" ? "" : weight}
                </h5>
              </div>
            </CardBody>
            <div className={classes.cardFooterInfo}>
              <Button simple color="primary" size="lg" onClick={handleEdit}>
                Edit
              </Button>
            </div>
          </div>
        ) : (
          <div>
            {/* edit mode */}
            <CardBody>
              <div>
                <FormControl fullWidth>
                  <InputLabel id="gender-label">Biological Gender</InputLabel>
                  <Select
                    labelId="gender-label"
                    id="gender"
                    value={gender}
                    onChange={(e) => setGender(e.target.value)}
                    endAdornment={
                      <InputAdornment position="end">
                        <Wc className={classes.inputIconsColor} />
                      </InputAdornment>
                    }
                  >
                    <MenuItem value={"Male"}>Male</MenuItem>
                    <MenuItem value={"Female"}>Female</MenuItem>
                    <MenuItem value={"Non-binary"}>Non-binary</MenuItem>
                  </Select>
                </FormControl>
              </div>

              <div>
                {/* <CustomInput
                  labelText="Athelete Type"
                  id="athleteType"
                  formControlProps={{
                    fullWidth: true,
                  }}
                  inputProps={{
                    type: "text",
                    value: athleteType,
                    onChange: (e) => setAtheleteType(e.target.value),
                    endAdornment: (
                      <InputAdornment position="end">
                        <FitnessCenter className={classes.inputIconsColor} />
                      </InputAdornment>
                    ),
                  }}
                /> */}
                <FormControl fullWidth>
                  <InputLabel id="athelete-type-label">
                    Athelete Type
                  </InputLabel>
                  <Select
                    labelId="athelete-type-label"
                    id="gender"
                    value={athleteType}
                    onChange={(e) => setAtheleteType(e.target.value)}
                    endAdornment={
                      <InputAdornment position="end">
                        <FitnessCenter className={classes.inputIconsColor} />
                      </InputAdornment>
                    }
                  >
                    <MenuItem value={"Runner"}>Runner</MenuItem>
                    <MenuItem value={"Cyclist"}>Cyclist</MenuItem>
                  </Select>
                </FormControl>
              </div>
              <div>
                <CustomInput
                  labelText="Location"
                  id="location"
                  formControlProps={{
                    fullWidth: true,
                  }}
                  inputProps={{
                    type: "text",
                    value: location,
                    onChange: (e) => setLocation(e.target.value),
                    endAdornment: (
                      <InputAdornment position="end">
                        <LocationOn className={classes.inputIconsColor} />
                      </InputAdornment>
                    ),
                  }}
                />
              </div>
              <div>
                <CustomInput
                  labelText="Height (cm)"
                  id="height"
                  formControlProps={{
                    fullWidth: true,
                  }}
                  inputProps={{
                    type: "text",
                    value: height,
                    onChange: (e) => setHeight(e.target.value),
                    endAdornment: (
                      <InputAdornment position="end">
                        <Height className={classes.inputIconsColor} />
                      </InputAdornment>
                    ),
                  }}
                />
              </div>
              <div>
                <CustomInput
                  labelText="Weight (kg)"
                  id="weight"
                  formControlProps={{
                    fullWidth: true,
                  }}
                  inputProps={{
                    type: "text",
                    value: weight,
                    onChange: (e) => setWeight(e.target.value),
                    endAdornment: (
                      <InputAdornment position="end">
                        <Person className={classes.inputIconsColor} />
                      </InputAdornment>
                    ),
                  }}
                />
              </div>
            </CardBody>
            <div className={classes.cardFooterEdit}>
              <Button simple color="primary" size="lg" onClick={handleCancel}>
                Cancel
              </Button>
              <Button simple color="primary" size="lg" onClick={handleSubmit}>
                Save
              </Button>
            </div>
          </div>
        )}
      </form>
    </Card>
  );
}