🐥
Webエンジニアへの道172日経過 - ポートフォリオアプリ ユーザー画面作成③
現在の学習状況
こんにちは、Someです!
まずは現在の学習状況をシェアしていきます。
※右にある数字は終了予定月と()内が完了実績月です。
- html・css 4月(4)
- Javascript 4月(4)
- Python 4月(4)
- Django 5月(5)
- git・github 5月(5)
- Linux 5月(5)
- DB・SQL 6月 (6)
- モダンJavaScript 6月(6)
- 業界研究、企業研究 7月(7)
- ポートフォリオアイデア 7月(7)
- PHP・Laravel基礎学習 7月(8)
- 安全なアプリケーション 8月(8)
- API 8月(8)
- ポートフォリオ作成開始 8月(8)←イマココ
- ポートフォリオ完成 10月
- 転職活動開始 10月
- 転職成功 12月
より詳細のロードマップ↓
(https://inquisitive-toy-f87.notion.site/519f079b4a34486781073b6f6b862572?v=13677f66b244447ea2ac02e6c6e455ca)
今週の学び・気付き
先週に引き続き、ポートフォリオアプリのユーザー画面を作成していきました!
ユーザートップ画面は盛り込む内容が非常に多いので、大苦戦しております。。。
献立設定画面
一週間分の献立を設定できる画面になります。
前回記事の見た目より、UI/UX向上を意識して作成しております。
コードはこちら↓
@php
use App\Models\UserDishes;
use App\Models\MenuOptions;
@endphp
<x-user-layout>
<div class="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 py-12">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="text-center mb-12">
<h1 class="text-4xl font-bold text-gray-900 mb-2">週間メニュープランナー</h1>
<p class="text-gray-600">1週間の献立を簡単に計画できます</p>
</div>
<!-- タブナビゲーション -->
<div id="tabs" class="flex justify-around space-x-2 rounded-full bg-yellow-500/20 p-2 mb-8">
@foreach(['Mon', 'Tues', 'Wednes', 'Thurs', 'Fri', 'Satur', 'Sun'] as $day)
<div class="tab w-full rounded-full py-3 text-lg font-semibold leading-5 text-blue-700 cursor-pointer text-center hover:bg-yellow-500 hover:text-white transition duration-300" data-tab="{{ $day }}">
{{ $day }}
</div>
@endforeach
</div>
<!-- タブコンテンツ -->
@foreach(['Mon', 'Tues', 'Wednes', 'Thurs', 'Fri', 'Satur', 'Sun'] as $day)
<div id="{{ $day }}" class="tab-content mt-6 hidden">
<div class="bg-white rounded-2xl shadow-lg overflow-hidden">
<!-- 現在のメニュー表示部分 -->
<div class="bg-gradient-to-r from-blue-500 to-indigo-600 p-6 text-white">
<h2 class="text-2xl font-bold mb-4">{{ $day }}曜日の現在の献立</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
@php
$mealTypes = [
['title' => 'メインメニュー', 'key' => 'main_dish_id', 'icon' => '🍽️'],
['title' => 'サブメニュー1', 'key' => 'sub_dish1_id', 'icon' => '🥗'],
['title' => 'サブメニュー2', 'key' => 'sub_dish2_id', 'icon' => '🥘']
];
@endphp
@foreach($mealTypes as $meal)
<div class="bg-white bg-opacity-10 backdrop-blur-lg rounded-xl p-4 border border-white border-opacity-20">
<div class="flex items-center mb-2">
<span class="text-2xl mr-2">{{ $meal['icon'] }}</span>
<h3 class="font-medium">{{ $meal['title'] }}</h3>
</div>
@php
// 最新の user_menus レコードを取得
$latestUserMenu = $userMenus->where('day_of_week', $day)
->sortByDesc('created_at') // created_at で降順にソート
->first(); // 最新のレコードを取得
// 各メニュータイプに対応する料理名を取得
$dishName = $latestUserMenu && $latestUserMenu->{$meal['key']}
? MenuOptions::find($latestUserMenu->{$meal['key']})->dish_name
: '未設定';
@endphp
<p class="text-lg font-semibold">{{ $dishName }}</p>
</div>
@endforeach
</div>
</div>
<!-- メニュー選択フォーム -->
<form action="{{ route('user.menu.keep') }}" method="POST" class="p-6">
@csrf
<input type="hidden" name="day_of_week" value="{{ $day }}">
<div class="mb-6">
<h2 class="text-2xl font-bold text-gray-900 mb-4">新しいメニューを選択</h2>
<p class="text-gray-600 mb-4">お好みのメニューを選択するか、ランダムに生成できます。</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
<h3 class="font-semibold mb-4 text-lg">メインメニュー <i class="fas fa-drumstick-bite ml-2 text-yellow-500"></i></h3>
<select name="main_menu" class="w-full p-3 border rounded-lg bg-yellow-50">
@if($mainMenus->isNotEmpty())
@foreach($mainMenus as $mainMenu)
<option value="{{ $mainMenu->menu_option_id }}">{{ $mainMenu->menuOption->dish_name }}</option>
@endforeach
@else
<option value="">No data available</option>
@endif
</select>
</div>
<div>
<h3 class="font-semibold mb-4 text-lg">サブメニュー1 <i class="fas fa-leaf ml-2 text-yellow-500"></i></h3>
<select name="sub_menu_1" class="w-full p-3 border rounded-lg bg-yellow-50">
@foreach($subMenus as $subMenu)
<option value="{{ $subMenu->menu_option_id }}">{{ $subMenu->menuOption->dish_name }}</option>
@endforeach
</select>
</div>
<div>
<h3 class="font-semibold mb-4 text-lg">サブメニュー2 <i class="fas fa-carrot ml-2 text-yellow-500"></i></h3>
<select name="sub_menu_2" class="w-full p-3 border rounded-lg bg-yellow-50">
@foreach($subMenus as $subMenu)
<option value="{{ $subMenu->menu_option_id }}">{{ $subMenu->menuOption->dish_name }}</option>
@endforeach
</select>
</div>
</div>
<div class="mt-8 flex space-x-4">
<button type="submit" class="keep flex-1 bg-blue-500 hover:bg-blue-600 text-white font-bold py-3 px-6 rounded-lg transition duration-300">
<i class="fas fa-save mr-2"></i>選択したメニューを保存
</button>
</form>
<!-- ランダムに保存 -->
<form action="{{ route('user.menu.randomkeep') }}" method="POST">
@csrf
<input type="hidden" name="day_of_week" value="{{ $day }}">
<button type="submit" class="random flex-1 bg-yellow-500 hover:bg-yellow-600 text-white font-bold py-3 px-6 rounded-lg transition duration-300">
<i class="fas fa-random mr-2"></i>ランダムに保存
</button>
</form>
</div>
</div>
</div>
@endforeach
{{-- <div class="mt-12 text-center">
<form action="{{ route('user.menu.weekrandom') }}" method="POST" class="inline-block">
@csrf
<button type="submit" id="week-random" class="bg-yellow-600 hover:bg-yellow-700 text-white font-bold py-3 px-8 rounded-lg transition duration-300">
<i class="fas fa-random mr-2"></i>1週間分をランダムに設定
</button>
</form>
</div> --}}
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$(document).ready(function() {
var activeTab = '{{ session('active_tab', 'Mon') }}';
// タブとコンテンツの初期化
$('.tab-content').addClass('hidden');
$('#' + activeTab).removeClass('hidden');
$('.tab').removeClass('bg-white shadow');
$('.tab[data-tab="' + activeTab + '"]').addClass('bg-white shadow');
// タブクリック時のイベント
$('.tab').click(function() {
var tab = $(this).data('tab');
$('.tab-content').addClass('hidden');
$('#' + tab).removeClass('hidden');
$('.tab').removeClass('bg-white shadow');
$(this).addClass('bg-white shadow');
});
});
</script>
</x-user-layout>
メニューを保存した時の曜日タブをそのままにするため、セッションを用いました。
献立候補設定画面
自分の環境において作る献立を選択できます。
ここでは献立候補と呼んでいます。
管理者が設定した献立候補が見られるようになっているので、今後はユーザーが献立候補を作成できるようにする予定です。
コードはこちら↓
@php
use App\Models\UserDishes;
@endphp
<x-user-layout>
<div class="container mx-auto px-2 py-4">
<div class="flex justify-between items-center mb-4">
<h1 class="text-xl font-bold text-gray-800">献立候補</h1>
<a href="{{ route('user.index') }}" class="bg-blue-500 hover:bg-blue-600 text-white text-xs font-bold py-1 px-3 rounded-full transition duration-300 ease-in-out transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50">
献立選択画面に戻る
</a>
</div>
@if (session('success'))
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-2 mb-3 text-xs" role="alert">
<p class="font-bold">成功</p>
<p>{{ session('success') }}</p>
</div>
@endif
@if (session('error'))
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-2 mb-3 text-xs" role="alert">
<p class="font-bold">エラー</p>
<p>{{ session('error') }}</p>
</div>
@endif
<div class="mb-4">
<h2 class="text-lg font-semibold mb-2 text-gray-700">メインメニュー</h2>
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-2">
@foreach ($menu_options->where('dish_type', 'main') as $menu_option)
@include('user.components.dish-card', ['menu_option' => $menu_option])
@endforeach
</div>
</div>
<div class="mb-4">
<h2 class="text-lg font-semibold mb-2 text-gray-700">サブメニュー</h2>
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-2">
@foreach ($menu_options->where('dish_type', 'sub') as $menu_option)
@include('user.components.dish-card', ['menu_option' => $menu_option])
@endforeach
</div>
</div>
</div>
</x-user-layout>
@php
use App\Models\UserDishes;
@endphp
@php
$userDishes = UserDishes::where('user_id', auth()->id())
->where('menu_option_id', $menu_option->id)
->first();
@endphp
<div class="bg-white rounded shadow-sm overflow-hidden transition duration-300 ease-in-out transform hover:-translate-y-1 hover:shadow-md relative">
@if ($userDishes)
<div class="absolute top-0 right-0 bg-green-500 text-white text-xs font-bold px-1 py-0.5 rounded-bl">追加済</div>
@endif
<div class="p-2">
<h5 class="text-sm font-semibold text-gray-800 mb-1 truncate" title="{{ $menu_option->dish_name }}">{{ $menu_option->dish_name }}</h5>
@if (!$userDishes)
<form action="{{ route('user.dishes.store') }}" method="POST">
@csrf
<input type="hidden" name="menu_option_id" value="{{ $menu_option->id }}">
<button type="submit" class="w-full bg-blue-500 hover:bg-blue-600 text-white text-xs font-bold py-2 px-2 rounded transition duration-300 ease-in-out transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50">
追加
</button>
</form>
@endif
@if ($userDishes)
<form action="{{ route('user.dishes.destroy', $userDishes->user_menu_id) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit" class="w-full bg-red-500 hover:bg-red-600 text-white text-xs font-bold py-2 px-2 rounded transition duration-300 ease-in-out transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-opacity-50">
削除
</button>
</form>
@endif
</div>
</div>
来週以降の進め方
今週は最も難しいと感じていた、曜日ごとの献立表示をある程度終えることができました!
やはり今の自分にとってはかなり難しく、AIの力なくして作ることはできませんでした。
しかしコードの意味はしっかり理解できているので、次に作るときには自分で書けるのではと思っています。
来週以降はユーザーにとって必ず必要な細かな項目を追加していき、まだまだ使い勝手が悪い部分を改善していきたいと思います!
それでは今回はこの辺で!
ありがとうございました!
Discussion