1

In my code I'm using a stepper with three steps first step is to select the template and the next step is to preview the selected template and put user input text on it. In order to get this done I need to pass the value of the selected template from SelectObituaryTemplate.js to PreviewObituary.js.

How can I get this done?

I have put the code for the buttons in the stepper as well -> StepperControl.js

SelectObituaryTemplates.js

import React, { useState } from 'react'
import ObituaryTemplateCard from '../ObituaryTemplateCard'

const SelectObituaryTemplates = () => {
  const [selectedTemplate, setSelectedTemplate] = useState(null);

  const handleSelectTemplate = (template) => {
    setSelectedTemplate(template);
  }
  return (
      <section className='bg-white'>
        <div className='container px-6 py-10 mx-auto'>
          <h1 className='text-2xl font-semibold text-center text-gray-800 capitalize lg:text-3xl'>
            Obituary Templates
          </h1>
          <div className='grid grid-cols-1 gap-8 mt-8 xl:mt-12 xl:gap-12 lg:grid-cols-2'>
          <ObituaryTemplateCard 
              template={{
                previewTemplateUrl: require("../../assets/obituary_templates/carnations_preview_template.png"),
                blankTemplateUrl: require("../../assets/obituary_templates/carnations_blank_template.png")
              }}
              isSelected={selectedTemplate === 'carnations'}
              onSelect={() => handleSelectTemplate('carnations')}
            />
            <ObituaryTemplateCard 
              template={{
                previewTemplateUrl: require("../../assets/obituary_templates/rose_preview_template.png"),
                blankTemplateUrl: require("../../assets/obituary_templates/rose_blank_template.png")
              }}
              isSelected={selectedTemplate === 'rose'}
              onSelect={() => handleSelectTemplate('rose')}
            />
          </div>
        </div>
      </section>
  )
}

export default SelectObituaryTemplates

CreateObituary.js

import React from 'react'

import { useState } from 'react'
import Stepper from '../components/Stepper'
import StepperControl from '../components/StepperControl'
import { UseContextProvider } from '../contexts/StepperContext'

import PreviewObituary from '../components/steps/PreviewObituary'
import SelectObituaryTemplate from '../components/steps/SelectObituaryTemplate'
import ShareObituary from '../components/steps/ShareObituary'

const CreateObituary = ({selectedTemplate}) => {
  const [currentStep, setCurrentStep] = useState(1)

  const steps = ['Select Obituary Template', 'Details of the Deceased', 'Preview']

  const displayStep = (step) => {
    switch (step) {
      case 1:
        return <SelectObituaryTemplate />
      case 2:
        return <PreviewObituary selectedTemplate={selectedTemplate} />
      case 3:
        return <ShareObituary />        
      default:
    }
  }

  const handleClick = (direction) => {
    let newStep = currentStep

    direction === 'next' ? newStep++ : newStep--
    // check if steps are within bounds
    newStep > 0 && newStep <= steps.length && setCurrentStep(newStep)
  }

  return (
    <div className='mx-auto rounded-2xl bg-white pb-2 my-6 shadow-xl md:w-3/4'>
      {/* Stepper */}
      <div className='horizontal container mt-5 '>
        <Stepper steps={steps} currentStep={currentStep} />

        <div className='my-10 p-10 '>
          <UseContextProvider>{displayStep(currentStep)}</UseContextProvider>
        </div>
      </div>

      {/* navigation button */}
      {currentStep !== steps.length && (
        <StepperControl
          handleClick={handleClick}
          selectedTemplate={selectedTemplate}
          currentStep={currentStep}
          steps={steps}
        />
      )}
    </div>
  )
}

export default CreateObituary

PreviewObituary.js

import React, { useState } from 'react'
import CarnationsBlankTemplate from '../../assets/obituary_templates/carnations_blank_template.png'
import RosesBlankTemplate from '../../assets/obituary_templates/rose_blank_template.png'

function PreviewObituary({ selectedTemplate }) {
  const [dob, setDob] = useState(null)
  const [dod, setDod] = useState(null)

  function handleDobChange(event) {
    setDob(new Date(event.target.value))
  }

  function handleDodChange(event) {
    setDod(new Date(event.target.value))
  }

  const [obituaryData, setObituaryData] = React.useState({
    firstName: '',
    lastName: '',
    dateOfBirth: '',
    dateOfDeath: '',
  })

  function handleChange(event) {
    const { name, value } = event.target
    setObituaryData((prevObituaryData) => ({
      ...prevObituaryData,
      [name]: value,
    }))
  }

  function handleDodCombinedChange(event) {
    handleChange(event)
    handleDodChange(event)
  }

  function handleDobCombinedChange(event) {
    handleChange(event)
    handleDobChange(event)
  }

  return (
    <section className='text-gray-600 body-font'>
      <div className='container px-5 py-24 mx-auto flex flex-wrap'>
        <div className='flex flex-wrap -m-4'>
          <div className='p-4 lg:w-1/2 md:w-full'>
            <div className='flex border-2 rounded-lg border-gray-200 border-opacity-50 p-8 sm:flex-row flex-col'>
              <div className='flex justify-center items-center gap-4 p-4 sm:p-6 lg:p-8'>
                {selectedTemplate === 'carnations' ? (
                  <img src={CarnationsBlankTemplate} className='w-full' />
                ) : (
                  <img src={RosesBlankTemplate} className='w-full' />
                )}
              </div>
            </div>
          </div>

          <div className='p-4 lg:w-1/2 md:w-full'>
            <div className='flex border-2 rounded-lg border-gray-200 border-opacity-50 p-8 sm:flex-row flex-col'>
              <form action='' className='mx-auto mb-0 w-full space-y-5'>
                <div class='grid grid-cols-1 gap-4 text-center sm:grid-cols-2'>
                  <div>
                    <label
                      for='FirstName'
                      class='block overflow-hidden rounded-md border border-gray-200 px-3 py-2 shadow-sm focus-within:border-blue-600 focus-within:ring-1 focus-within:ring-blue-600'
                    >
                      <span class='text-xs font-medium text-gray-700'>
                        {' '}
                        First Name{' '}
                      </span>

                      <input
                        type='text'
                        placeholder='John'
                        class='mt-1 w-full border-none p-0 focus:border-transparent focus:outline-none focus:ring-0 sm:text-sm'
                        name='firstName'
                        value={obituaryData.firstName}
                        onChange={handleChange}
                      />
                    </label>
                  </div>

                  <div>
                    <label
                      for='LastName'
                      className='block overflow-hidden rounded-md border border-gray-200 px-3 py-2 shadow-sm focus-within:border-blue-600 focus-within:ring-1 focus-within:ring-blue-600'
                    >
                      <span class='text-xs font-medium text-gray-700'>
                        {' '}
                        Last Name{' '}
                      </span>

                      <input
                        type='text'
                        placeholder='Doe'
                        class='mt-1 w-full border-none p-0 focus:border-transparent focus:outline-none focus:ring-0 sm:text-sm'
                        name='lastName'
                        value={obituaryData.lastName}
                        onChange={handleChange}
                      />
                    </label>
                  </div>
                </div>

                <div>
                  <label
                    for='UserImage'
                    class='block overflow-hidden rounded-md border border-gray-200 px-3 py-2 shadow-sm focus-within:border-blue-600 focus-within:ring-1 focus-within:ring-blue-600 file:bg-gray-200 file:text-gray-700 file:text-sm file:px-4 file:py-1 file:border-none file:rounded-full'
                  >
                    <span class='text-xs font-medium text-gray-700'>
                      {' '}
                      Image{' '}
                    </span>
                    <input
                      type='file'
                      id='UserImage'
                      className='w-full py-2 mt-2 text-sm text-gray-600 bg-white rounded-lg file:bg-gray-200 file:text-gray-700 file:text-sm file:px-4 file:py-1 file:border-none file:rounded-full'
                      accept='image/*'
                    />
                  </label>
                </div>

                <div class='grid grid-cols-1 gap-6 mt-4 sm:grid-cols-2'>
                  <div>
                    <label
                      for='DateOfBirth'
                      className='block overflow-hidden rounded-md border border-gray-200 px-3 py-2 shadow-sm focus-within:border-blue-600 focus-within:ring-1 focus-within:ring-blue-600'
                    >
                      <span class='text-xs font-medium text-gray-700'>
                        {' '}
                        Date of Birth{' '}
                      </span>

                      <input
                        type='Date'
                        class='mt-1 w-full border-none p-0 focus:border-transparent focus:outline-none focus:ring-0 sm:text-sm'
                        name='dateOfBirth'
                        value={obituaryData.dateOfBirth}
                        onChange={handleDobCombinedChange}
                      />
                    </label>
                  </div>

                  <div>
                    <label
                      for='DateOfDeath'
                      class='block overflow-hidden rounded-md border border-gray-200 px-3 py-2 shadow-sm focus-within:border-blue-600 focus-within:ring-1 focus-within:ring-blue-600'
                    >
                      <span class='text-xs font-medium text-gray-700'>
                        {' '}
                        Date of Death{' '}
                      </span>

                      <input
                        type='Date'
                        class='mt-1 w-full border-none p-0 focus:border-transparent focus:outline-none focus:ring-0 sm:text-sm'
                        name='dateOfDeath'
                        value={obituaryData.dateOfDeath}
                        onChange={handleDodCombinedChange}
                      />
                    </label>
                  </div>
                </div>

                <div className='mt-1 -space-y-px bg-white rounded-md shadow-sm'>
                  <div>
                    <label htmlFor='Epitaphs' className='sr-only'>
                      Epitaphs
                    </label>
                    <select
                      id='Epitaphs'
                      className='relative w-full border-gray-200 rounded-t-md focus:z-10 sm:text-sm'
                    >
                      <option>Forever in our hearts</option>
                      <option>Rest in peace</option>
                      <option>A life well lived</option>
                    </select>
                  </div>
                </div>
              </form>
            </div>
          </div>
        </div>
      </div>

      <div>
        <h2 className='obituaryText firstName'>{obituaryData.firstName}</h2>
        <h2 className='obituaryText lastName'>{obituaryData.lastName}</h2>
        {dob && (
          <h2 className='obituaryText dateOfBirth'>
            {dob.toLocaleDateString('en-US', {
              month: 'long',
              day: 'numeric',
              year: 'numeric',
            })}
          </h2>
        )}
        <h2 className='obituaryText'>-</h2>
        {dod && (
          <h2 className='obituaryText dateOfDeath'>
            {dod.toLocaleDateString('en-US', {
              month: 'long',
              day: 'numeric',
              year: 'numeric',
            })}
          </h2>
        )}
      </div>
    </section>
  )
}

export default PreviewObituary

StepperControl.js

export default function StepperControl({ handleClick, currentStep, steps}) {
  return (
    <div className='container mt-4 mb-8 flex justify-around'>
      <button
        onClick={() => handleClick()}
        className={`cursor-pointer rounded-xl border-2 border-slate-300 bg-white py-2 px-4 font-semibold uppercase text-slate-400 transition duration-200 ease-in-out hover:bg-slate-700 hover:text-white  ${
          currentStep === 1 ? ' cursor-not-allowed opacity-50 ' : ''
        }`}
      >
        Back
      </button>

      {currentStep === steps.length - 1 ? (
        <button
          onClick={() => handleClick('next')}
          className='inline-flex w-full items-center justify-center rounded-lg bg-black px-5 py-3 text-white sm:w-auto'
        >
          Confirm
          <svg
            xmlns='http://www.w3.org/2000/svg'
            class='ml-3 h-5 w-5'
            fill='none'
            viewBox='0 0 24 24'
            stroke='currentColor'
          >
            <path
              stroke-linecap='round'
              stroke-linejoin='round'
              stroke-width='2'
              d='M14 5l7 7m0 0l-7 7m7-7H3'
            />
          </svg>
        </button>
      ) : (
        <button
          onClick={() => handleClick('next')}
          className='inline-flex w-full items-center justify-center rounded-lg bg-black px-5 py-3 text-white sm:w-auto'
        >
          Next
          <svg
            xmlns='http://www.w3.org/2000/svg'
            class='ml-3 h-5 w-5'
            fill='none'
            viewBox='0 0 24 24'
            stroke='currentColor'
          >
            <path
              stroke-linecap='round'
              stroke-linejoin='round'
              stroke-width='2'
              d='M14 5l7 7m0 0l-7 7m7-7H3'
            />
          </svg>
        </button>
      )}
    </div>
  )
}
meow
  • 33
  • 6

1 Answers1

0

You need to instantiate selectedTemplate in the CreateObituary component, which is the parent component to SelectObituaryTemplates and PreviewObituary components. Then you can pass the state value and event handler to update it as props.

const CreateObituary = ({selectedTemplate}) => {
  const [currentStep, setCurrentStep] = useState(1)
  const [selectedTemplate, setSelectedTemplate] = useState(null);

  const handleClick = (direction) => {
    let newStep = currentStep

    direction === 'next' ? newStep++ : newStep--
    // check if steps are within bounds
    newStep > 0 && newStep <= steps.length && setCurrentStep(newStep)
  }

  const steps = ['Select Obituary Template', 'Details of the Deceased', 'Preview']

  const displayStep = (step) => {
    switch (step) {
      case 1:
        return <SelectObituaryTemplate selectedTemplate={selectedTemplate} handleClick={handleClick} />
      case 2:
        return <PreviewObituary selectedTemplate={selectedTemplate} />
      case 3:
        return <ShareObituary />        
      default:
    }
  }

  // ...

Read more here.