React Resume - uploader Website (Geekyshows)
Tags: javascript, react, beginners, express
Published: 2022-12-13 16:53:44

## FrontEnd Redux Code: :- 



**Folder Structure:-**
![Folder Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m5ddurfi6qf42llsfc8k.png)


**Output Image :-**
![Output Photo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fcdw1rku3bwtseycjlr6.png)


**index.js code :-**

``` react
// import { CssBaseline } from '@mui/material';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { store } from './app/store'
import { Provider } from 'react-redux'

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
```

**store.js code :-**

``` react
import { configureStore } from '@reduxjs/toolkit'
// Or from '@reduxjs/toolkit/query/react'
import { setupListeners } from '@reduxjs/toolkit/query'
import { candidateProfileApi } from '../services/candidateProfileApi'

export const store = configureStore({
    reducer: {
        // Add the generated reducer as a specific top-level slice
        [candidateProfileApi.reducerPath]: candidateProfileApi.reducer,
    },
    // Adding the api middleware enables caching, invalidation, polling,
    // and other useful features of `rtk-query`.
    middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware().concat(candidateProfileApi.middleware),
})

// optional, but required for refetchOnFocus/refetchOnReconnect behaviors
// see `setupListeners` docs - takes an optional callback as the 2nd arg for customization
setupListeners(store.dispatch)
```

**candidateProfileApi.js Code:-**

``` react
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'

// Define a service using a base URL and expected endpoints
export const candidateProfileApi = createApi({
    reducerPath: "candidateProfileApi",
    baseQuery: fetchBaseQuery({ baseUrl: "http://127.0.0.1:8000/" }),
    endpoints: (builder) => ({
        saveProfile: builder.mutation({
            query: (candidate) => {
                return {
                    url: "api/resume",
                    method: "POST",
                    body: candidate
                }
            },
        }),
        getResumeProfile: builder.query({
            query: () => {
                return {
                    url: "api",
                    method: "GET",
                }
            },
        }),
    }),
})

// Export hooks for usage in functional components, which are
// auto-generated based on the defined endpoints
export const { useSaveProfileMutation, useGetResumeProfileQuery } = candidateProfileApi;
```

**App.js code :-**

``` react
import React from 'react'

import { format } from 'date-fns';
import { useState } from 'react'
import { Box, Grid, Typography } from "@mui/material";
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import Paper from '@mui/material/Paper';
import Avatar from '@mui/material/Avatar';
import TextField from '@mui/material/TextField';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import Select from '@mui/material/Select';
import Radio from '@mui/material/Radio';
import RadioGroup from '@mui/material/RadioGroup';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormControl from '@mui/material/FormControl';
import FormLabel from '@mui/material/FormLabel';
import Checkbox from '@mui/material/Checkbox';
import FormGroup from '@mui/material/FormGroup';
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';

import MuiAlert from '@mui/material/Alert';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';

import Snackbar from '@mui/material/Snackbar';
import IconButton from '@mui/material/IconButton';
import CloseIcon from '@mui/icons-material/Close';

import { useSaveProfileMutation, useGetResumeProfileQuery } from './services/candidateProfileApi';

function App() {

  const [profiledata, setprofiledata] = useState([]);
  // eslint-disable-next-line 
  const [name, setName] = useState("");

  // eslint-disable-next-line 
  const [email, setEmail] = useState("");

  // eslint-disable-next-line 
  const [gender, setGender] = useState("");

  const [loc, setLoc] = useState([]);

  const getLocation = async (e) => {
    const { checked, value } = e.target;
    console.log("1loc", loc);

    if (checked) {
      await setLoc((item) => [...item, value]);
    } else {
      await setLoc(loc.filter((e) => e !== value));
    }

    console.log("2loc", loc);
  }

  const [error, setError] = useState({
    status: false,
    color: "",
    msg: ""
  })


  const [pimage, setpimage] = useState("");
  const handlepimage = (e) => {
    setpimage(e.target.files[0])
  }
  const [rdoc, setrdoc] = useState("");

  const [date, setDate] = useState(null);
  const handleDate = (newValue) => {
    setDate(newValue);
  };

  const [state, setState] = React.useState('');
  const handlestate = (event) => {
    setState(event.target.value);
  };


  // RTK Query
  const [profile, responseInfo] = useSaveProfileMutation();
  const { data } = useGetResumeProfileQuery();

  React.useEffect(() => {
    if (data) {

      setprofiledata(data.candidates)
    }
  }, [data])

  const handleSubmit = async (e) => {


    e.preventDefault();
    const form = new FormData();

    form.append("name", name);
    form.append("email", email);
    form.append("dob", date);
    form.append("state", state);
    form.append("gender", gender);
    form.append("location", loc);
    form.append("pimage", pimage);
    form.append("rdoc", rdoc);

    if (name && email && date && state && gender && loc && pimage && rdoc) {

      const res = await profile(form);
      console.log(res)

      if (res.data.status === "success") {

        setError({
          status: true,
          color: "success",
          msg: "Form Submitted Successfully"
        })
        setOpen(true);

      }
      clearForm()
    } else {
      console.log(`name: ${form.get("name")}, email:- ${form.get("email")}, date:- ${form.get("date")}, state:-  ${form.get("state")}, gender:-  ${form.get("gender")}, location:- ${form.get("pjl")}, image:
      - ${form.get("pimage")}, doc:- ${form.get("rdoc")}`)
      console.log(form.get("pimage"));

      setError({
        status: true,
        color: "error",
        msg: "All Fields are Required"
      })
      setOpen(true);
    }
  };

  const [open, setOpen] = React.useState(false);
  const handleClose = (event, reason) => {
    if (reason === 'clickaway') {
      return;
    }
    setOpen(false);
  };

  // eslint-disable-next-line
  const action = (
    <React.Fragment>
      <IconButton
        size="small"
        aria-label="close"
        color="inherit"
        onClick={handleClose}
      >
        <CloseIcon fontSize="small" />
      </IconButton>
    </React.Fragment>
  );

  const Alert = React.forwardRef(function Alert(props, ref) {
    return <MuiAlert elevation={6} ref={ref} variant="filled" {...props} />;
  });

  const clearForm = () => {
    setName("");
    setEmail("");
    setDate(null);
    setGender("");
    setLoc([]);
    setpimage("");
    setrdoc("");
    setState("");

    document.getElementById("resume-form").reset();
  }

  const vertical = "bottom";
  const horizontal = "right";
  return (
    <>

      {/* Mui snackbar  */}
      <Snackbar open={open} anchorOrigin={{ vertical, horizontal }} autoHideDuration={7000} onClose={handleClose} key="bottomright">
        <Alert onClose={handleClose} severity={error.color} sx={{ width: '100%' }}>
          {error.msg}
        </Alert>
      </Snackbar>

      <Box display="flex" justifyContent="center" sx={{ backgroundColor: "error.light", textAlign: "center" }}>
        <Typography variant="h3" component="div" sx={{ fontWeight: "bold", color: "white" }}> Resume Uploader </Typography>
      </Box>

      <Grid container justifyContent='center'>
        <Grid item xs={12} md={5}>

          <Box component="form" noValidate id="resume-form" sx={{ p: 3 }} onSubmit={handleSubmit}>
            <TextField id="name" label="Name" autoFocus variant="outlined" name="name" margin="normal" required fullWidth value={name} onChange={(e) => setName(e.target.value)} />
            <TextField id="email" value={email} label="Email" variant="outlined" name="email" required fullWidth onChange={(e) => setEmail(e.target.value)} />

            {/* Date time picker  */}
            <Box mt={2}>
              <LocalizationProvider dateAdapter={AdapterDayjs}>
                <DateTimePicker
                  label="Date&Time picker"
                  // inputFormat="dd/mm/yyyy  hh:mm a|pm"
                  value={date}
                  onChange={handleDate}
                  renderInput={(params) => <TextField {...params} />}
                />
              </LocalizationProvider>
            </Box>

            {/* Select State Component  */}
            <FormControl fullWidth margin='normal'>
              <InputLabel id="demo-simple-select-label">State</InputLabel>
              <Select
                labelId="demo-simple-select-label"
                id="demo-simple-select"
                value={state}
                label="Age"
                onChange={handlestate}
              >
                <MenuItem value="Gujarat">Gujarat</MenuItem>
                <MenuItem value="Rajkot">Rajkot</MenuItem>
                <MenuItem value="Bangladesh">Bangladesh</MenuItem>
              </Select>
            </FormControl>

            {/* Gender Component  */}
            <FormControl fullWidth margin='normal'>
              <FormLabel id="demo-row-radio-buttons-group-label">Gender</FormLabel>
              <RadioGroup
                row
                aria-labelledby="demo-row-radio-buttons-group-label"
                name="gender"
              >
                <FormControlLabel value="female" onChange={((e) => setGender(e.target.value))} control={<Radio />} label="Female" />
                <FormControlLabel value="male" onChange={((e) => setGender(e.target.value))} control={<Radio />} label="Male" />
                <FormControlLabel value="other" onChange={((e) => setGender(e.target.value))} control={<Radio />} label="Other" />
              </RadioGroup>
            </FormControl>

            {/* Multiple Checkbox  */}
            <FormControl margin="normal">
              <FormLabel> Prefered Job Location</FormLabel>

              <FormGroup row>
                <FormControlLabel onChange={(e) => getLocation(e)} control={<Checkbox color='secondary' />} label="Delhi" value="Delhi" />
                <FormControlLabel onChange={(e) => getLocation(e)} control={<Checkbox color='warning' />} label="Mumbai" value="Mumbai" />
                <FormControlLabel onChange={getLocation} control={<Checkbox color='success' />} label="Banglore" value="Banglore" />
                <FormControlLabel onChange={getLocation} control={<Checkbox color='primary' />} label="Ranchi" value="Ranchi" />
                <FormControlLabel onChange={getLocation} control={<Checkbox />} label="Kolkata" value="Kolkata" />
              </FormGroup>
            </FormControl>

            {/* Upload Button  */}
            <Stack direction="row" alignItems="center" spacing={2}>
              <Button variant="contained" component="label">
                UPLOAD PHOTO
                <input hidden onChange={handlepimage} accept="image/*" name='aksh' id='profile-photo' type="file" />
              </Button>

              <Button variant="contained" component="label">
                UPLOAD FILE
                <input hidden accept="doc/*" onChange={(e) => setrdoc(e.target.files[0])} id='resume-file' type="file" />
              </Button>
            </Stack>

            {/* Submit Button  */}
            {/* <Button type='submit' variant='contained' sx={{ mt: 2, px: 5 }} color="error"> Submit </Button> */}

            {responseInfo.isLoading ? <Button disabled type='submit' variant='contained' sx={{ mt: 2, px: 5 }} color="error"> Submit </Button> : <Button type='submit' variant='contained' sx={{ mt: 2, px: 5 }} color="error"> Submit </Button>}
          </Box>
        </Grid>

        <Grid item xs={12} md={7} sx={{ mt: 4 }} >
          <Box display="flex" justifyContent="center" sx={{ backgroundColor: "info.light", }} padding="1">
            <Typography variant="h5" component="div" sx={{ fontWeight: 'bold', color: "white" }}>
              List of Candidate
            </Typography>
          </Box>

          {/* Table Component  */}
          <TableContainer component={Paper}>
            <Table sx={{ minWidth: 650 }} aria-label="simple table">
              <TableHead>
                <TableRow sx={{ backgroundColor: "secondary.dark" }}>
                  <TableCell align="center"> Name </TableCell>
                  <TableCell align="center"> Email </TableCell>
                  <TableCell align="center"> DOB </TableCell>
                  <TableCell align="center"> State </TableCell>
                  <TableCell align="center"> Gender </TableCell>
                  <TableCell align="center"> Location </TableCell>
                  <TableCell align="center"> Profile </TableCell>
                </TableRow>
              </TableHead>
              <TableBody>

                {profiledata.map((item, index) => {
                  return <TableRow
                    key={index}
                    sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
                  >
                    <TableCell component="th" scope="row">
                      {item.name}
                    </TableCell>
                    <TableCell align="center"> {item.email} </TableCell>
                    <TableCell align="center"> {format(new Date(item.dob), 'dd-MM-yyyy')} </TableCell>
                    <TableCell align="center"> {item.state} </TableCell>
                    <TableCell align="center"> {item.gender} </TableCell>
                    <TableCell align="center"> {item.location} </TableCell>
                    <TableCell align="center" >  <Avatar alt="Aksh desai" src={`http://127.0.0.1:8000/${item.pimage}`} /> </TableCell>
                    <TableCell align="center" >
                      <iFrame src={`http://127.0.0.1:8000/${item.rdoc}`}> aksh </iFrame>

                    </TableCell>
                  </TableRow>
                })}

              </TableBody>
            </Table>
          </TableContainer>
        </Grid>

      </Grid>
    </>
  );
}

export default App;

```