Skip to content
2 changes: 1 addition & 1 deletion apps/web/app/components/namecard/CreationProcess.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const { color } = useColor()
}"
class="title"
>
{{ t('namecard.creation-process.title') }}
{{ t('namecard.creation_process.title') }}
</h2>
<ol
:style="{
Expand Down
48 changes: 34 additions & 14 deletions apps/web/app/components/namecard/CreationStatus.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ const { color } = useColor()
export type Status = 'not_created' | 'inquiry_in_progress' | 'inquiry_failed' | 'inquiry_completed'
type Props = {
statusKey: Status
size?: 'small' | 'medium'
}
const props = defineProps<Props>()
const props = withDefaults(defineProps<Props>(), {
size: 'medium',
})

const backgroundColor = computed(() => {
switch (props.statusKey) {
Expand All @@ -24,29 +27,46 @@ const backgroundColor = computed(() => {
return color('gray/100')
}
})

const style = computed(() => {
const baseStyle = {
color: color('white'),
backgroundColor: backgroundColor.value,
}
switch (props.size) {
case 'small':
return {
...baseStyle,
height: '24px',
borderRadius: '24px',
padding: '0 20px',
fontWeight: fontWeight('heading/700'),
fontSize: fontSize('body/100'),
}
default:
return {
...baseStyle,
height: '38px',
borderRadius: '38px',
padding: '0 38px',
fontWeight: fontWeight('heading/700'),
fontSize: fontSize('heading/200'),
}
}
})
</script>

<template>
<div
class="creation-status-root"
:style="{
fontWeight: fontWeight('heading/700'),
fontSize: fontSize('heading/200'),
color: color('white'),
backgroundColor: backgroundColor,
}"
>
<div class="creation-status-root" :style="style">
{{ t(`namecard.creation_status.${statusKey}`) }}
</div>
</template>

<style scoped>
.creation-status-root {
display: flex;
display: inline-flex;
justify-content: center;
align-items: center;
width: 166px;
height: 38px;
border-radius: 38px;
line-height: 1;
}
</style>
213 changes: 202 additions & 11 deletions apps/web/app/components/namecard/ImageUploader.vue
Original file line number Diff line number Diff line change
@@ -1,25 +1,216 @@
<script setup lang="ts">
import { useTypography } from '@vuejs-jp/composable'
import { useI18n } from '#i18n'
import { onMounted, ref } from 'vue'
import { useColor, useTypography } from '@vuejs-jp/composable'

type Props = {
label: string
interface DragDropProps {
fileAccept: string
}
defineProps<Props>()

defineProps<DragDropProps>()
const isDragEnter = ref(false)

const emit = defineEmits<{
'check-files': [e: Event, value: File[]]
}>()

const fileName = ref<string | null>()

const { t } = useI18n()
const onDropFile = (e: DragEvent) => {
e.preventDefault()
if (e.dataTransfer?.files) {
fileName.value = e.dataTransfer.files[0].name
emit('check-files', e, Array.from(e.dataTransfer.files))
}
}

function handleCloseButton(e: Event) {
fileName.value = null
emit('check-files', e, [])
}

const onFileInputChange = (event: Event) => {
event.preventDefault()
const { target } = event
if (!(target instanceof HTMLInputElement)) return

if (target.files) {
fileName.value = target.files[0].name
emit('check-files', event, Array.from(target.files))
}
}

const { color: updateColor } = useColor()
const { fontWeight, fontSize } = useTypography()

onMounted(() => {
window.ondrop = (e) => {
e.preventDefault()
}
window.ondragover = (e) => {
e.preventDefault()
}
})
</script>

<template>
<!-- TODO 画像アップローダーのブラッシュアップ -->
<VFDragDropArea
<label
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀

既存のものは使えなかったんですかね

for="fileupload"
class="drag-drop-area-root"
:style="{
fontSize: fontSize('body/300'),
fontWeight: fontWeight('heading/100'),
fontSize: fontSize('heading/100'),
color: updateColor('vue-green/200'),
}"
>
{{ label }}
<VFCssResetButton class="select-button" />
</VFDragDropArea>
{{ t('namecard.form.label_avatar') }}
<div v-if="fileName" class="file-name-area">
<p class="file-name">{{ fileName }}</p>
<VFIconButton
class="icon-close"
color="vue-blue"
name="close"
can-hover
@click="handleCloseButton"
/>
</div>
<button
v-else
draggable="true"
class="drag-drop-area"
:class="{ '-isDragEnter': isDragEnter }"
@dragenter="() => (isDragEnter = true)"
@dragleave="() => (isDragEnter = false)"
@dragover.prevent
@drop.prevent="onDropFile"
>
<div class="message-area">
<p
class="label"
:style="{
fontSize: fontSize('body/400'),
fontWeight: fontWeight('heading/200'),
color: updateColor('vue-blue'),
}"
>
{{ t('namecard.form.drag_and_drop') }}
</p>
<p
class="label or"
:style="{
fontSize: fontSize('body/200'),
fontWeight: fontWeight('body/300'),
color: updateColor('vue-blue'),
}"
>
{{ t('namecard.form.or') }}
</p>
</div>
<input
id="fileUpload"
class="select-button"
type="file"
name="avatar"
:accept="fileAccept"
@change="onFileInputChange"
/>
</button>
<p
class="annotation"
:style="{
fontSize: fontSize('body/300'),
fontWeight: fontWeight('body/300'),
color: updateColor('vue-blue'),
}"
>
{{ t('namecard.form.annotation_avatar') }}
</p>
<!-- TODO エラー制御
<Typography v-if="errorMessage" variant="body/200" color="sangosyo/200">{{
errorMessage
}}</Typography> -->
</label>
</template>

<style scoped></style>
<style scoped>
@import url('~/assets/media.css');

.drag-drop-area-root {
display: inline-block;
}
.drag-drop-area {
width: 100%;
margin: calc(var(--unit) * 1.5) auto;
border: 1px solid #e1e1e1;
border-radius: 6px;
background-color: #fff;
color: var(--color-vue-blue);
}
.drag-drop-area:hover {
transition: 0.2s;
box-shadow: 0 2px 10px rgba(53, 73, 94, 14%);
}
.file-name-area {
width: 100%;
margin: calc(var(--unit) * 1.5) auto;
border: 1px solid #e1e1e1;
border-radius: 6px;
background: #c6cacf40;
color: var(--color-vue-blue);
padding: calc(var(--unit) * 3);
display: flex;
justify-content: space-between;
align-items: center;
}
.file-name {
flex-grow: 1;
text-align: center;
}
.icon-close {
display: inline-block;
text-align: right;
height: 22px;
}
.message-area {
display: inline-flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: var(--height-input-area);
width: 100%;
padding: calc(var(--unit) * 3) calc(var(--unit) * 3) 0;
text-align: center;
}
.label {
margin-bottom: calc(var(--unit) * 1.5);
}
#fileUpload {
font-size: 0;
}
::file-selector-button {
--height-button: 50px;

display: inline-flex;
justify-content: center;
align-items: center;

font-size: var(--font-size-body400);
font-weight: 700;
color: var(--color-vue-blue);
background-color: var(--color-white);

height: var(--height-button);
padding: 0 43px;
margin: 0 auto calc(var(--unit) * 3);
border: 2px solid var(--color-vue-blue);
border-radius: var(--height-button);
cursor: pointer;
}
::file-selector-button:hover {
transition: 0.2s;
color: var(--color-white);
background-color: var(--color-vue-blue);
box-shadow: 0 2px 10px rgba(53, 73, 94, 14%);
}
</style>
6 changes: 1 addition & 5 deletions apps/web/app/composables/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,5 @@ export function useAuth() {
return data.user
}

const authUserId = getUser().then(user => {
return user.id
}).catch(()=> null)

return { signIn, signOut, authUserId }
return { signIn, signOut, getUser }
}
1 change: 1 addition & 0 deletions apps/web/app/composables/useLocale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export function useLocale(path: Path) {
.with('namecard_process_3', () => `/${locale.value}/namecard_process_3`)
.with('namecard_process_4', () => `/${locale.value}/namecard_process_4`)
.with('namecard_process_alert', () => `/${locale.value}/namecard_process_alert`)
.with('namecard_annotation_order_number', () => `/${locale.value}/namecard_annotation_order_number`)
.exhaustive(),
)

Expand Down
49 changes: 49 additions & 0 deletions apps/web/app/composables/useNamecard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { computed } from 'vue'
import { useSupabase, useAsyncData, useAuth } from '#imports'
import type { Status } from '~/components/namecard/CreationStatus.vue'
import type { Attendee } from '@vuejs-jp/model'


export async function useNamecard(userId?:string) {
const { fetchAttendeeDataByUserId } = useSupabase()
const { getUser } = useAuth()

const { data: authUserId } = await useAsyncData('authUserId', async () => {
return (await getUser()).id
})

const { data: attendeeByUserId } = await useAsyncData('attendeeByUserId', async () => {
return await fetchAttendeeDataByUserId('attendees', authUserId.value ?? userId ?? '')
})

const userData = computed(() => {
return attendeeByUserId.value?.data?.[0]
})

const statusKey = computed<Status>(() => {
// TODO テーブルのどの箇所を参照して全ステータスを判定する?
if (userData.value?.activated_at) {
return 'inquiry_in_progress'
} else {
return 'not_created'
}
})

const attendee = computed<Attendee>(() => {
// TODO time 系は空文字じゃない方が良い。supabase側で設定できるのか、フロント側でnew Date使うのか?
return {
id: userData.value?.id ?? '',
user_id: userData.value?.user_id ?? '',
activated_at: userData.value?.activated_at ?? '',
created_at: userData.value?.created_at ?? '',
updated_at: userData.value?.updated_at ?? '',
display_name: userData.value?.display_name ?? '',
email: userData.value?.email ?? '',
provider: userData.value?.provider ?? '',
avatar_url: userData.value?.avatar_url ?? '',
role: userData.value?.role ?? '',
receipt_id: userData.value?.receipt_id ?? '',
}
})
return { authUserId, userData, statusKey, attendee }
}
5 changes: 5 additions & 0 deletions apps/web/app/composables/useSupabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export function useSupabase() {
return await client.from(table).select().eq('role', role)
}

async function fetchAttendeeDataByUserId(table: Extract<Table, 'attendees'>, userId:string) {
return await client.from(table).select().eq('user_id', userId)
}

async function upsertSpeaker(table: Extract<Table, 'speakers'>, target: FormSpeaker) {
const targetData = { ...target }

Expand Down Expand Up @@ -65,6 +69,7 @@ export function useSupabase() {
return {
fetchData,
fetchAttendeeData,
fetchAttendeeDataByUserId,
upsertSpeaker,
upsertSponsor,
upsertJob,
Expand Down
Loading
Loading