laravelの認証機構を見てみよう(13) : userのcrudを仕上げる(6) - SMデバイスの対応
実は相当これ厳しい
とりあえすブレークポイントをスモールデバイスに設定して、ほぼほぼの機能のviewを確認していってみよう
メニューが欠落している問題
まずこのようにダッシュボード以外の導線がないのと、まあよくみりゃProfileが英語になっている。これはAuthenticatedLayoutで小さいデバイスの対応をちゃんと更新してないからであーる。
まあ具体的にはこのヘン
<div className="hidden sm:flex sm:items-center sm:ml-6">
<div className="ml-3 relative">
<Dropdown>
<Dropdown.Trigger>
<span className="inline-flex rounded-md">
<button
type="button"
className="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150"
>
{user.name}
<svg
className="ml-2 -mr-0.5 h-4 w-4"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</button>
</span>
</Dropdown.Trigger>
<Dropdown.Content>
<Dropdown.Link href={route('profile.edit')}>{t("Profile")}</Dropdown.Link>
<Dropdown.Link href={route('logout')} method="post" as="button">
{t("Log Out")}
</Dropdown.Link>
</Dropdown.Content>
</Dropdown>
</div>
</div>
まずこれであるが
<div className="hidden sm:flex sm:items-center sm:ml-6">
ここの
<div className="hidden sm:flex">a</div>
これは基本的にhiddenなんだけどsm以上で表示されるつまり、モバイルビューでは表示されない。この部分もせっかくreact-iconsがあるので適当に設定しておいた
<div className="hidden sm:flex sm:items-center sm:ml-6">
<div className="ml-3 relative">
<Dropdown>
<Dropdown.Trigger>
<span className="inline-flex rounded-md">
<button
type="button"
className="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150"
>
{user.name}
<VscCheronDown className="ml-2"/>
</button>
</span>
</Dropdown.Trigger>
<Dropdown.Content>
<Dropdown.Link href={route('profile.edit')}>{t("Profile")}</Dropdown.Link>
<Dropdown.Link href={route('logout')} method="post" as="button">
{t("Log Out")}
</Dropdown.Link>
</Dropdown.Content>
</Dropdown>
</div>
</div>
この区域はokだろう。次
<div className="-mr-2 flex items-center sm:hidden">
<button
onClick={() => setShowingNavigationDropdown((previousState) => !previousState)}
className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out"
>
<svg className="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
<path
className={!showingNavigationDropdown ? 'inline-flex' : 'hidden'}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M4 6h16M4 12h16M4 18h16"
/>
<path
className={showingNavigationDropdown ? 'inline-flex' : 'hidden'}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
このまぎらわしいのは
<div className="-mr-2 flex items-center sm:hidden">
のsm:hiddenであろう。これはsmをhiddenにするのではなくその逆であるw
smブレークポイント以上をhiddenにするのだ。従ってひらたく言うとこのdivはモバイル向けということ。ここはメニューの開閉とstateの設定である。vscにして意味が通りやすいようにした
<div className="-mr-2 flex items-center sm:hidden">
<button
onClick={() => setShowingNavigationDropdown((previousState) => !previousState)}
className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out"
>
<VscMenu className={!showingNavigationDropdown ? 'inline-flex' : 'hidden'} />
<VscClose className={showingNavigationDropdown ? 'inline-flex' : 'hidden'} />
</button>
</div>
その次
<div className={(showingNavigationDropdown ? 'block' : 'hidden') + ' sm:hidden'}>
<div className="pt-2 pb-3 space-y-1">
<ResponsiveNavLink href={route('dashboard')} active={route().current('dashboard')}>
{t("Dashboard")}
</ResponsiveNavLink>
{auth.isAdmin && (
<ResponsiveNavLink href={route('users.index')} active={route().current('users.*')}>
{t("Users")}
</ResponsiveNavLink>
)}
</div>
<div className="pt-4 pb-1 border-t border-gray-200">
<div className="px-4">
<div className="font-medium text-base text-gray-800">{user.name}</div>
<div className="font-medium text-sm text-gray-500">{user.email}</div>
</div>
<div className="mt-3 space-y-1">
<ResponsiveNavLink href={route('profile.edit')}>Profile</ResponsiveNavLink>
<ResponsiveNavLink method="post" href={route('logout')} as="button">
{t("Log Out")}
</ResponsiveNavLink>
</div>
</div>
</div>
<div className={(showingNavigationDropdown ? 'block' : 'hidden') + ' sm:hidden'}>
これも基本的にはsm:hiddenなのでスマホ用である。おぼえておこう
ここのメニューが足りてないので単純に増やす
<div className={(showingNavigationDropdown ? 'block' : 'hidden') + ' sm:hidden'}>
<div className="pt-2 pb-3 space-y-1">
<ResponsiveNavLink href={route('dashboard')} active={route().current('dashboard')}>
{t("Dashboard")}
</ResponsiveNavLink>
{auth.isAdmin && (
<ResponsiveNavLink href={route('users.index')} active={route().current('users.*')}>
{t("Users")}
</ResponsiveNavLink>
)}
</div>
<div className="pt-4 pb-1 border-t border-gray-200">
<div className="px-4">
<div className="font-medium text-base text-gray-800">{user.name}</div>
<div className="font-medium text-sm text-gray-500">{user.email}</div>
</div>
<div className="mt-3 space-y-1">
<ResponsiveNavLink href={route('profile.edit')}>Profile</ResponsiveNavLink>
<ResponsiveNavLink method="post" href={route('logout')} as="button">
{t("Log Out")}
</ResponsiveNavLink>
</div>
</div>
</div>
アイコンとか付けときます?
<div className={(showingNavigationDropdown ? 'block' : 'hidden') + ' sm:hidden'}>
<div className="pt-2 pb-3 space-y-1">
<ResponsiveNavLink href={route('dashboard')} active={route().current('dashboard')}>
<VscDashboard className="mr-2" /> {t("Dashboard")}
</ResponsiveNavLink>
{auth.isAdmin && (
<ResponsiveNavLink href={route('users.index')} active={route().current('users.*')}>
<VscOrganization className="mr-2" /> {t("Users")}
</ResponsiveNavLink>
)}
</div>
<div className="pt-4 pb-1 border-t border-gray-200 bg-gray-100">
<div className="px-4">
<div className="font-medium text-base text-gray-800">{user.name}</div>
<div className="font-medium text-sm text-gray-500">{user.email}</div>
</div>
<div className="mt-3 space-y-1">
<ResponsiveNavLink href={route('profile.edit')}>
<VscNote className="mr-2" /> {t("Profile")}
</ResponsiveNavLink>
<ResponsiveNavLink method="post" href={route('logout')} as="button">
<VscIndent className="mr-2" /> {t("Log Out")}
</ResponsiveNavLink>
</div>
</div>
</div>
この辺りは好みで
ユーザー一覧とかのtableがめりこんでいる
とりあえず
<div className="bg-white overflow-auto shadow-sm sm:rounded-lg">
overflow-autoにしとけばまあ表示はされる。ただ、ここはもうちょい調整が必要かもしれないね。
失敗してるテストを直してとりあえずこの項目は終わり
まずTests\Feature\ProfileTestが落ちとる
% ./vendor/bin/sail test tests/Feature/ProfileTest.php
FAIL Tests\Feature\ProfileTest
✓ profile page is displayed 1.84s
✓ profile information can be updated 0.06s
✓ email verification status is unchanged when the email address is unchanged 0.03s
⨯ user can delete their account 0.12s
✓ correct password must be provided to delete account 0.10s
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
FAILED Tests\Feature\ProfileTest > user can delete their account
Failed asserting that App\Models\User Object #3642 (
'connection' => 'mysql'
'table' => 'users'
'primaryKey' => 'id'
'keyType' => 'int'
'incrementing' => true
'with' => Array &0 ()
'withCount' => Array &1 ()
'preventsLazyLoading' => false
'perPage' => 15
'exists' => true
'wasRecentlyCreated' => false
'escapeWhenCastingToString' => false
'attributes' => Array &2 (
これは削除してもエントリーがのこってるぞっつってるので単純に論理削除にしたことに対してテストが追いついてない。
// SoftDeleteを考慮し、ユーザがSoft Deletedされたかを確認する
$this->assertNotNull($user->fresh()->deleted_at);
とまあこんな感じであとちょいと手直ししたけど、ま、長くなったので今日はここまでで。