habte's avatar
Level 4

The profile photo field must be a file problem using InertiaJS for React & Laravel app.

` class ApplicationController extends Controller {

public function index()
{
    return Inertia::render('Admin/Applicants/Index', [
        'applicants' => Application::count(),
        'applicants_data' => Application::all(),
        'message' => session('message'),
    ]);
}

public function create()
{
    $sectors = Sector::with('occupations')->get();
    return Inertia::render('Apply/Index', [
        'sectors' => $sectors
    ]);
}

public function store(ApplicationStoreRequest $request)
{
    $data = $request->validated();

    $image_one = $data['high_school_transcript'];
    $image_two = $data['gslce_result'];
    $image_three = $data['profile_photo'];

    $data['high_school_transcript_path'] = $image_one->store('applicants/transcript/' . Str::random(), 'public');
    $data['gslce_result_path'] = $image_two->store('applicants/result/' . Str::random(), 'public');
    $data['profile_photo'] = $image_three->store('applicants/profile/' . Str::random(), 'public');

    Application::create($data);

    return to_route('/home')
        ->with('message', 'The Application Sent Successfully');
}

public function show()
{
    //
}

public function edit(string $id)
{
    $applicant = Application::find($id);
    $sectors = Sector::with('occupations')->get();
    $trainees = User::where('role', 'trainee')->get();

    return Inertia::render('Admin/Applicants/Edit', [
        'applicant' => $applicant,
        'sectors' => $sectors,
        'trainees' => $trainees,
    ]);
}

public function update(ApplicationStoreRequest $request, Application $application)
{
    $data = $request->validated();
    $image_one = $data['high_school_transcript'];
    $image_two = $data['gslce_result'];
    $image_three = $data['profile_photo'];

    if ($application) {

        if ($image_one) {
            Storage::deleteDirectory(dirname($application->high_school_transcript_path));
            $image_one = $image_one->store('applicants/transcript/' . Str::random(), 'public');
        }

        if ($image_two) {
            Storage::deleteDirectory(dirname($application->gslce_result_path));
            $image_two = $image_two->store('applicants/result/' . Str::random(), 'public');
        }

        if ($image_three) {
            Storage::deleteDirectory(dirname($application->profile_photo));
            $image_three = $image_three->store('applicants/profile/' . Str::random(), 'public');
        }
    }

    $application->update($data);

    return to_route('admin.applicants.index')->with('message', "$application->first_name's application updated");
}

public function destroy(Request $request, Application $application)
{
    $request->validate([
        'password' => 'required|current_password'
    ]);

    if ($application) {
        Storage::deleteDirectory(dirname($application->high_school_transcript_path));
        Storage::deleteDirectory(dirname($application->gslce_result_path));
        Storage::deleteDirectory(dirname($application->profile_photo));

        $application->delete();

        return redirect()->route('admin.applicants.index')
            ->with('message', 'Application deleted successfully');
    }

    return redirect()->route('admin.applicants.index');
}

} `

the above is my application controller. I am focused on the update method.

` class ApplicationStoreRequest extends FormRequest { /** * Determine if the user is authorized to make this request. */ public function authorize(): bool { return true; }

/**
 * Get the validation rules that apply to the request.
 *
 * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
 */
public function rules(): array
{
    return [
       '.......',
        'high_school_transcript' => [$this->isMethod('post') ? 'required' : 'nullable', 'file', 'mimes:png,jpg,pdf,jpeg', 'max:5120'],
        'gslce_result' => [$this->isMethod('post') ? 'required' : 'nullable', 'file', 'mimes:png,jpg,pdf,jpeg', 'max:5120'],
        'profile_photo' => [$this->isMethod('post') ? 'required' : 'nullable', 'file', 'mimes:png,jpg,pdf,jpeg', 'max:5120'],
        '.....',
    ];
}

} `

the above is the application store and update Request method ApplicationStoreRequest.

the below is the frontend:

` const [confirmApplicantDeletion, setConfirmApplicantDeletion] = useState(false); const [deletingApplicant, setDeletingApplicant] = useState(null); const passwordInput = useRef('');

const { data, setData, delete: destroy, put, processing, reset, errors, } = useForm({ high_school_transcript: applicant.high_school_transcript, gslce_result: applicant.gslce_result, profile_photo: applicant.profile_photo, });

const refreshUsername = (enrollmentType, email) => { setUsername(generateUsername(enrollmentType, email)); };

const closeModal = () => { setConfirmApplicantDeletion(false); setDeletingApplicant(null); reset(); };

const confirmModalApplicantDeletion = (applicant) => { setDeletingApplicant(applicant); setConfirmApplicantDeletion(true); };

const delApplicant = (applicant, e) => { e.preventDefault();

destroy(route('admin.applicant.destroy', applicant), { preserveScroll: true, onSuccess: () => closeModal(), onError: () => passwordInput.current.focus(), onFinish: () => reset(), }); };

const submit = (e) => { e.preventDefault(); put(route('admin.applicants.update', applicant)); };

            <InputError
              className='mt-2'
              message={errors.high_school_transcript}
            />
          </div>
        </div>
      ) : (
        <>
          <div className='max-medium:w-full max-medium:mt-4'>
            <InputLabel
              value='High School Transcript'
              htmlFor='high_school_transcript'
              className='mb-2'
            />
            <TextInput
              type='file'
              name='high_school_transcript'
              id='high_school_transcript'
              onChange={(e) =>
                setData('high_school_transcript', e.target.files[0])
              }
              className='p-2 mt-1 block w-full desktop:max-w-md'
            />

            <InputError
              className='mt-2'
              message={errors.high_school_transcript}
            />
          </div>
        </>
      )}
      {initialData.gslce_result_path ? (
        <div className='flex flex-col'>
          <a
            target='_blank'
            href={`${window.location.origin}/storage/${initialData.gslce_result_path}`}
            className='flex items-center justify-center rounded relative bg-gray-200 w-full max-h-[150px] min-h-[150px] text-black py-4 hover:bg-gray-300 dark:bg-neutral-700 dark:hover:bg-neutral-600 dark:text-white group'
          >
            <IoDocumentAttach size={31} />
            <LiaExternalLinkAltSolid
              size={20}
              className='absolute bottom-1 right-1'
            />
            <p className='text-[14px] absolute inline-flex scale-50 opacity-0 group-hover:opacity-100 group-hover:scale-100 transition items-center justify-center bg-white/90 inset-0 backdrop-blur-sm text-center dark:bg-black/70'>
              Review High School Transcript
            </p>
          </a>
          <div className='max-medium:w-full max-medium:mt-4 mt-1'>
            <InputLabel
              value='Update GSLCE Result'
              htmlFor='gslce_result'
              className='text-nowrap mb-2'
            />
            <TextInput
              type='file'
              id='gslce_result'
              name='gslce_result'
              onChange={(e) => setData('gslce_result', e.target.files[0])}
              className='p-2 mt-1 block w-full desktop:max-w-md'
            />

            <InputError className='mt-2' message={errors.gslce_result} />
          </div>
        </div>
      ) : (
        <div className='max-medium:w-full max-medium:mt-4'>
          <InputLabel
            value='GSLCE Result'
            htmlFor='gslce_result'
            className='text-nowrap mb-2'
          />
          <TextInput
            type='file'
            id='gslce_result'
            name='gslce_result'
            onChange={(e) => setData('gslce_result', e.target.files[0])}
            className='p-2 mt-1 block w-full desktop:max-w-md'
          />

          <InputError className='mt-2' message={errors.gslce_result} />
        </div>
      )}
      {initialData.profile_photo ? (
        <div className='flex flex-col gap-1'>
          <img
            src={`http://127.0.0.1:8000/storage/${initialData.profile_photo}`}
            alt=''
            className='inline-block w-full max-w-[150px] max-h-[150px] min-h-[150px] object-cover rounded hover:scale-[1.02] transition'
          />
          <div className='max-medium:w-full max-medium:mt-4'>
            <InputLabel
              value='Update Passport size photo'
              htmlFor='profile_photo'
              className='text-nowrap mb-2'
            />
            <TextInput
              type='file'
              id='profile_photo'
              name='profile_photo'
              onChange={(e) => setData('profile_photo', e.target.files[0])}
              className='p-2 mt-1 block w-full desktop:max-w-md'
            />

            <InputError className='mt-2' message={errors.profile_photo} />
          </div>
        </div>
      ) : (
        <div className='max-medium:w-full max-medium:mt-4'>
          <InputLabel
            value='Passport size photo'
            htmlFor='profile_photo'
            className='text-nowrap mb-2'
          />
          <TextInput
            type='file'
            id='profile_photo'
            name='profile_photo'
            onChange={(e) => setData('profile_photo', e.target.files[0])}
            className='p-2 mt-1 block w-full desktop:max-w-md'
          />

          <InputError className='mt-2' message={errors.profile_photo} />
        </div>
      )}
    </div>
  </FieldSet>

`

This is my second time experiencing this problem, at first I just went okay by not solving it. but now I am in the place where I have to work it out. AI isn't helping me out here.

encType='multipart/form-data' isn't working here since its inertiaJS https://inertiajs.com/file-uploads

Please help

0 likes
0 replies

Please or to participate in this conversation.