Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: membershipページを作成 #20

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
9 changes: 9 additions & 0 deletions src/composable/parseRouteQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { LocationQueryValue } from 'vue-router'

export const parseRouteQuery = (query: LocationQueryValue | LocationQueryValue[]) => {
if (Array.isArray(query)) {
return query.filter((v): v is string => typeof v === 'string')
} else {
return typeof query === 'string' ? [query] : ['']
}
}
11 changes: 11 additions & 0 deletions src/pages/login/LoginPage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script setup lang="ts">
import { parseRouteQuery } from '@/composable/parseRouteQuery'
import { useRoute } from 'vue-router'

const route = useRoute()
const redirectParams = parseRouteQuery(route.query.redirect)
</script>

<template>
<RouterLink :to="redirectParams[0]"> ログインする </RouterLink>
</template>
17 changes: 17 additions & 0 deletions src/pages/membership/MemberShipPageUserTypeSelector.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script setup lang="ts">
import MemberShipPageUserTypeSelectorButton from './MemberShipPageUserTypeSelectorButton.vue'
</script>

<template>
<div class="flex gap-2">
<MemberShipPageUserTypeSelectorButton userType="new">
新規入部
</MemberShipPageUserTypeSelectorButton>
<MemberShipPageUserTypeSelectorButton userType="rejoin">
再入部
</MemberShipPageUserTypeSelectorButton>
<MemberShipPageUserTypeSelectorButton userType="active">
継続所属
</MemberShipPageUserTypeSelectorButton>
</div>
</template>
19 changes: 19 additions & 0 deletions src/pages/membership/MemberShipPageUserTypeSelectorButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router'
import type { UserType } from './types/userType'

const { userType } = defineProps<{ userType: UserType }>()

const route = useRoute()
const router = useRouter()
const replaceUserTypeQuery = (userType: UserType) => {
const newQuery = { ...route.query, user_type: userType }
router.replace({ query: newQuery })
}
</script>

<template>
<button @click="replaceUserTypeQuery(userType)">
<slot></slot>
</button>
</template>
82 changes: 80 additions & 2 deletions src/pages/membership/MembershipPage.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,83 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useRoute } from 'vue-router'

import MemberShipPageVerifyEmailLink from '@/pages/membership/MembershipPageVerifyEmailLink.vue'
import MemberShipPageUserTypeSelector from './MemberShipPageUserTypeSelector.vue'
import MembershipPageInputText from './MembershipPageInputText.vue'
import MembershipPageLoginLink from './MembershipPageLoginLink.vue'

const route = useRoute()

const isUserTypeNew = computed(() => route.query.user_type === 'new')
const isUserTypeRejoin = computed(() => route.query.user_type === 'rejoin')
const isUserTypeActive = computed(() => route.query.user_type === 'active')
const isUserTypeQueryValid = computed(
() => isUserTypeNew.value || isUserTypeRejoin.value || isUserTypeActive.value,
)

const isLoggedIn = ref(false)
const hasVerifiedMailAddress = ref(true)
const hasCustomerObjectOnTraqId = ref(false)
const shouldShowUserTypeSelector = computed(() => !isLoggedIn.value)
const needUserTypeSelect = computed(() => !isLoggedIn.value && !isUserTypeQueryValid.value)
const needMailAddressInput = computed(
() =>
(isLoggedIn.value && !hasCustomerObjectOnTraqId.value && !hasVerifiedMailAddress.value) ||
(!isLoggedIn.value &&
(isUserTypeNew.value || isUserTypeRejoin.value) &&
!hasVerifiedMailAddress.value),
)
const needLogin = computed(() => isUserTypeActive.value && !isLoggedIn.value)

const hasCustomerObjectOnMailAddress = ref(false)
const hasTraQIdOnCustomerObject = ref(false)
const hasCustomerObject = computed(
() => hasCustomerObjectOnMailAddress.value || hasCustomerObjectOnTraqId.value,
)
const canShowInvoiceForm = computed(
() =>
(isLoggedIn.value && (hasCustomerObjectOnTraqId.value || hasVerifiedMailAddress.value)) ||
(!isLoggedIn.value &&
(isUserTypeNew.value || isUserTypeRejoin.value) &&
hasVerifiedMailAddress.value),
)
const needTraqIdInput = computed(
() =>
isUserTypeRejoin.value &&
(!hasCustomerObjectOnMailAddress.value || !hasTraQIdOnCustomerObject.value),
)
const traqIdInput = ref('')
const needNameInput = computed(() => !hasCustomerObject.value)
const nameInput = ref('')
const hasValidTraqId = computed(() => !needTraqIdInput.value || traqIdInput.value.length > 0)
const hasName = computed(() => !needNameInput.value || nameInput.value.length > 0)
const canShowInvoiceInfoConfirm = computed(
() => needNameInput.value && hasValidTraqId.value && hasName.value,
)
</script>

<template>
<div>
<h1>This is an membership page</h1>
<div class="flex flex-col gap-2">
<div v-if="shouldShowUserTypeSelector">
<MemberShipPageUserTypeSelector />
</div>
<div v-if="needUserTypeSelect">新規入部、再入部、継続所属のいずれかを選択してください</div>
<div v-if="needMailAddressInput" class="flex flex-col gap-2">
isct アドレスの認証が必要です <MemberShipPageVerifyEmailLink />
</div>
<div v-if="needLogin" class="flex flex-col gap-2">
ログインが必要です
<MembershipPageLoginLink />
</div>
<div v-if="canShowInvoiceForm && needTraqIdInput" class="flex flex-col gap-2">
traQ ID を入力してください
<MembershipPageInputText v-model="traqIdInput" />
</div>
<div v-if="canShowInvoiceForm && needNameInput" class="flex flex-col gap-2">
名前を入力してください
<MembershipPageInputText v-model="nameInput" />
</div>
<div v-if="canShowInvoiceInfoConfirm">請求書発行のための情報を確認してください</div>
</div>
</template>
36 changes: 36 additions & 0 deletions src/pages/membership/MembershipPageInputText.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script setup lang="ts">
import { onMounted, useTemplateRef } from 'vue'

const model = defineModel<string>({ required: true })
const { autoFocus, className, required, placeholder } = withDefaults(
defineProps<{
autoFocus?: boolean
className?: string
required?: boolean
placeholder?: string
}>(),
{
autoFocus: false,
className: 'rounded border px-1',
required: false,
placeholder: '',
},
)
const inputRef = useTemplateRef('input-ref')

onMounted(() => {
if (autoFocus) {
inputRef.value?.focus()
}
})
</script>

<template>
<input
ref="input-ref"
:class="className"
:placeholder="placeholder"
:required="required"
v-model="model"
/>
</template>
13 changes: 13 additions & 0 deletions src/pages/membership/MembershipPageLoginLink.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script setup lang="ts">
import { useRoute } from 'vue-router'

const route = useRoute()
const getLoginPageURL = {
path: '/login',
query: { redirect: route.fullPath },
}
</script>

<template>
<RouterLink :to="getLoginPageURL">ログインへ</RouterLink>
</template>
13 changes: 13 additions & 0 deletions src/pages/membership/MembershipPageVerifyEmailLink.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script setup lang="ts">
import { useRoute } from 'vue-router'

const route = useRoute()
const getVerifyEmailPageURL = {
path: '/verify-email',
query: { redirect: route.fullPath },
}
</script>

<template>
<RouterLink :to="getVerifyEmailPageURL">isct アドレスの認証へ</RouterLink>
</template>
1 change: 1 addition & 0 deletions src/pages/membership/types/userType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type UserType = 'new' | 'rejoin' | 'active'
11 changes: 11 additions & 0 deletions src/pages/verify-email/VerifyEmailPage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script setup lang="ts">
import { parseRouteQuery } from '@/composable/parseRouteQuery'
import { useRoute } from 'vue-router'

const route = useRoute()
const redirectParams = parseRouteQuery(route.query.redirect)
</script>

<template>
<RouterLink :to="redirectParams[0]"> isct アドレスを認証する </RouterLink>
</template>
10 changes: 10 additions & 0 deletions src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ const router = createRouter({
// which is lazy-loaded when the route is visited.
component: () => import('@/pages/membership/MembershipPage.vue'),
},
{
path: '/verify-email',
name: 'verify-email',
component: () => import('@/pages/verify-email/VerifyEmailPage.vue'),
},
{
path: '/login',
name: 'login',
component: () => import('@/pages/login/LoginPage.vue'),
},
],
})

Expand Down
Loading