Skip to content

Commit

Permalink
feat(mobile): add navigation toolbar (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
mtthp authored Nov 24, 2023
1 parent a542120 commit 040d0e3
Show file tree
Hide file tree
Showing 13 changed files with 178 additions and 85 deletions.
6 changes: 3 additions & 3 deletions src/components/layout/NavigationDrawer.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<template>
<aside class="hidden w-28 flex-col items-center overflow-y-auto bg-amber-500 py-6 md:flex">
<div class="flex shrink-0 items-center">
<aside class="flex w-28 flex-col items-center overflow-y-auto bg-amber-500">
<div class="mt-6 flex shrink-0 items-center max-sm:hidden">
<img
alt="Your Company"
class="h-8 w-auto"
src="https://tailwindui.com/img/logos/mark.svg?color=white" />
</div>
<nav class="mt-6 flex w-full grow flex-col gap-1 px-2">
<nav class="my-6 flex w-full grow flex-col gap-1 px-2">
<router-link
v-for="item in sidebarNavigation"
:key="item.label"
Expand Down
22 changes: 21 additions & 1 deletion src/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
import * as frenchMessages from './locales/fr-FR';
import dayjs from 'dayjs';
import calendar from 'dayjs/plugin/calendar.js';
import LocalizedFormat from 'dayjs/plugin/localizedFormat.js';
import relativeTime from 'dayjs/plugin/relativeTime.js';
import updateLocale from 'dayjs/plugin/updateLocale.js';
import { createI18n, IntlDateTimeFormats, IntlNumberFormats } from 'vue-i18n';
import 'dayjs/locale/fr.js';
import 'dayjs/locale/en-gb.js';
dayjs.extend(updateLocale);
dayjs.extend(calendar);
dayjs.extend(relativeTime);
dayjs.extend(LocalizedFormat);

dayjs.updateLocale('fr', {
calendar: {
lastDay: '[Hier à] LT',
sameDay: "[Aujourd'hui à] LT",
nextDay: '[Demain à] LT',
lastWeek: 'dddd [dernier à] LT',
nextWeek: 'dddd [prochain à] LT',
sameElse: 'L',
},
});

const datetimeFormats: IntlDateTimeFormats = {
'fr-FR': {
Expand Down Expand Up @@ -32,7 +51,6 @@ const numberFormats: IntlNumberFormats = {
};

const defaultLang = import.meta.env.VUE_APP_DEFAULT_LOCALE || 'fr-FR';
dayjs.locale(defaultLang.substring(0, 2));

export const i18nInstance = createI18n({
globalInjection: true,
Expand Down Expand Up @@ -61,3 +79,5 @@ export const changeLocale = async (lang: string): Promise<string> => {

return setI18nLanguage(lang);
};

setI18nLanguage(defaultLang);
4 changes: 3 additions & 1 deletion src/i18n/locales/fr-FR/members.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"attendance": {
"description": "Les présences de ce membre au cours des 6 derniers mois.\nLes présences sont enregistrées automatiquement lorsque le membre se connecte au réseau wifi du coworking.",
"last30days": {
"empty": "Absent",
"label": "Présent",
"suffix": "jour | seul jour | jours",
"value": "{amount} sur les 30 derniers jours"
Expand Down Expand Up @@ -64,11 +65,12 @@
},
"macAddresses": {
"add": "Spécifier un appareil | Ajouter un autre appareil | Ajouter un autre appareil",
"check": "Vérifier",
"description": {
"link": "adresse MAC",
"text": "Permet de connaître la présence au travers d'une {link}"
},
"label": "Appareil | Appareils",
"label": "Appareil | Appareil | Appareils",
"remove": "Retirer"
},
"phone": {
Expand Down
2 changes: 2 additions & 0 deletions src/i18n/locales/fr-FR/navigation.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"close": "Fermer le menu",
"members": "@:members.list.title",
"open": "Ouvrir le menu",
"stats": "@:stats.title"
}
51 changes: 29 additions & 22 deletions src/services/api/members.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,56 @@ import HTTP from '../http';
export const COUPON_UNIT_COST_IN_EUR = 6 as const;
export const SUBSCRIPTION_UNIT_COST_IN_EUR = 60 as const;

export interface MemberListItem {
id: number;
picture: string;
email: string;
phone: string;
firstname: string;
lastname: string;
lastSeen: string;
balance: number;
subscription: {
startDate: string;
endDate: string;
purchased: string;
};
memberships: {
purchaseDate: string;
membershipStart: string;
}[];
macAddresses: string[];
}

export interface Coupon {
id: string;
purchaseDate: string;
tickets: number;
}

export interface Subscription {
id: string;
startDate: string;
endDate: string;
purchased: string;
}

export interface Attendance {
id: string;
date: string;
amount: number;
type: 'SUBSCRIPTION' | 'COUPON';
type: 'SUBSCRIPTION' | 'TICKET';
}

export interface Membership {
id: string;
purchaseDate: string;
membershipStart: string;
}

export interface Device {
id: string;
macAddress: string;
}

export interface MemberListItem {
id: number;
picture: string;
email: string;
phone: string;
firstname: string;
lastname: string;
lastSeen: string;
balance: number;
subscription: Subscription;
}

export interface Member extends MemberListItem {
created: string;
tickets: Coupon[];
presences: Attendance[];
subscriptions: Subscription[];
devices: Device[];
memberships: Membership[];
}

export const getAllMembers = (): Promise<MemberListItem[]> => {
Expand Down
4 changes: 1 addition & 3 deletions src/views/Private/Members/Detail/CouponsPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<div class="flex flex-row flex-wrap items-center justify-between gap-1 px-4 py-5 sm:p-6">
<h4 class="text-lg font-medium">{{ $t('members.detail.orders.coupons.title') }}</h4>
<span
class="rounded-full bg-indigo-500/10 px-3 py-1 text-sm font-semibold leading-6 text-indigo-400 ring-1 ring-inset ring-indigo-500/20">
class="rounded-full bg-indigo-500/10 px-3 py-1 text-sm leading-6 text-indigo-400 ring-1 ring-inset ring-indigo-500/20">
{{ $t('members.detail.orders.coupons.remaining', { count: remaining }) }}
</span>
</div>
Expand Down Expand Up @@ -54,9 +54,7 @@ import { COUPON_UNIT_COST_IN_EUR, Coupon } from '@/services/api/members';
import SvgIcon from '@jamescoyle/vue-icon';
import { mdiPlus } from '@mdi/js';
import dayjs from 'dayjs';
import LocalizedFormat from 'dayjs/plugin/localizedFormat.js';
import { PropType } from 'vue';
dayjs.extend(LocalizedFormat);
defineProps({
coupons: {
Expand Down
Empty file.
48 changes: 27 additions & 21 deletions src/views/Private/Members/Detail/ProfilePanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,17 @@

<div class="flex flex-col">
<p class="block text-sm font-medium text-gray-700">
{{
$t('members.detail.profile.macAddresses.label', { count: state.macAddresses.length })
}}
{{ $t('members.detail.profile.macAddresses.label', { count: state.devices.length }) }}
</p>
<i18n-t
class="block text-gray-500"
keypath="members.detail.profile.macAddresses.description.text"
scope="global"
tag="small">
<template #link>
<a
class="font-medium text-blue-600 hover:underline dark:text-blue-500"
href=""
href="https://www.studentinternet.eu/fr/docs/nederlands/depannage/comment-puis-je-trouver-ladresse-mac-de-mon-appareil/"
target="_blank">
{{ $t('members.detail.profile.macAddresses.description.link') }}
</a>
Expand All @@ -67,8 +66,8 @@
</i18n-t>
<ul class="mt-1 flex flex-col gap-6">
<li
v-for="(macAddress, index) in state.macAddresses"
:key="`mac-address-${macAddress}`"
v-for="(device, index) in state.devices"
:key="`device-${device.id}`"
class="flex rounded-md shadow-sm">
<div class="relative flex grow items-stretch focus-within:z-10">
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
Expand All @@ -79,10 +78,23 @@
type="mdi" />
</div>
<input
v-model="state.macAddresses[index].address"
v-model="state.devices[index].macAddress"
class="block w-full rounded-none rounded-l-md border-gray-300 pl-10 uppercase focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
placeholder="A0:B1:C2:D3:E4:F5"
type="text" />

<a
v-if="state.devices[index].macAddress"
class="absolute inset-y-0 right-0 flex items-center pr-3 text-sm font-medium text-blue-600 hover:underline dark:text-blue-500 max-sm:hidden"
:href="`https://maclookup.app/search/result?mac=${state.devices[index].macAddress}`"
target="_blank">
{{ $t('members.detail.profile.macAddresses.check') }}
<SvgIcon
aria-hidden="true"
class="ml-1 inline-block h-5 w-5"
:path="mdiOpenInNew"
type="mdi" />
</a>
</div>
<button
class="relative -ml-px inline-flex items-center gap-x-2 rounded-r-md border border-gray-300 bg-gray-50 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
Expand All @@ -102,9 +114,7 @@
type="button"
@click="onAddMacAddress">
<SvgIcon aria-hidden="true" class="mr-3 h-5 w-5" :path="mdiPlus" type="mdi" />
{{
$t('members.detail.profile.macAddresses.add', { count: state.macAddresses.length })
}}
{{ $t('members.detail.profile.macAddresses.add', { count: state.devices.length }) }}
</button>
</li>
</ul>
Expand Down Expand Up @@ -161,7 +171,7 @@
</SwitchGroup>
</ul>
</div>
<div class="flex flex-row bg-gray-50 px-4 py-3 sm:px-6">
<div class="flex flex-row border-t-[1px] border-gray-200 bg-gray-50 px-4 py-3 sm:px-6">
<AppButton :icon="mdiCheckAll" type="submit">
{{ $t('action.apply') }}
</AppButton>
Expand All @@ -172,7 +182,7 @@
<script setup lang="ts">
import AppButton from '@/components/form/AppButton.vue';
import AppTextField from '@/components/form/AppTextField.vue';
import { Member } from '@/services/api/members';
import { Device, Member } from '@/services/api/members';
import { Switch, SwitchDescription, SwitchGroup, SwitchLabel } from '@headlessui/vue';
import SvgIcon from '@jamescoyle/vue-icon';
import { mdiClose, mdiLaptop, mdiCheckAll, mdiPlus, mdiOpenInNew } from '@mdi/js';
Expand All @@ -181,10 +191,6 @@ import { required, email } from '@vuelidate/validators';
import { watch } from 'vue';
import { PropType, reactive } from 'vue';
interface MacAddress {
address: string;
}
const props = defineProps({
member: {
type: Object as PropType<Member>,
Expand All @@ -197,7 +203,7 @@ const state = reactive({
lastname: null as string | null,
email: null as string | null,
phone: null as string | null,
macAddresses: [] as MacAddress[],
devices: [] as Device[],
isManager: false as boolean,
hasParkingAccess: false as boolean,
});
Expand All @@ -211,15 +217,15 @@ const rules = {
const vuelidate = useVuelidate(rules, state);
const onAddMacAddress = () => {
state.macAddresses.push({ address: '' });
state.devices.push({ id: '', macAddress: '' });
};
const onRemoveMacAddress = (index: number) => {
state.macAddresses.splice(index, 1);
state.devices.splice(index, 1);
};
const onSubmit = () => {
console.log(state.macAddresses);
// TODO: vuelidate and call the API
};
watch(
Expand All @@ -230,7 +236,7 @@ watch(
state.lastname = member.lastname || null;
state.email = member.email || null;
state.phone = member.phone || null;
state.macAddresses = member.macAddresses.map((address) => ({ address })) || [];
state.devices = member.devices || null;
}
},
{ immediate: true },
Expand Down
4 changes: 2 additions & 2 deletions src/views/Private/Members/Detail/SectionRow.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<template>
<section class="flex flex-row flex-wrap gap-3 px-3">
<section class="flex flex-row flex-wrap gap-3">
<aside class="flex min-w-[12rem] shrink grow basis-0 flex-col">
<slot name="title">
<h2 v-if="title" class="text-xl font-medium leading-6 text-gray-900">
{{ title }}
</h2>
</slot>
<slot name="title">
<slot name="description">
<p v-if="description" class="mt-1 whitespace-pre-line text-sm text-gray-600">
{{ description }}
</p>
Expand Down
4 changes: 1 addition & 3 deletions src/views/Private/Members/Detail/SubscriptionsPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<div class="flex flex-row flex-wrap items-center justify-between gap-1 px-4 py-5 sm:p-6">
<h4 class="text-lg font-medium">{{ $t('members.detail.orders.subscriptions.title') }}</h4>
<span
class="rounded-full bg-indigo-500/10 px-3 py-1 text-sm font-semibold leading-6 text-indigo-400 ring-1 ring-inset ring-indigo-500/20">
class="rounded-full bg-indigo-500/10 px-3 py-1 text-sm leading-6 text-indigo-400 ring-1 ring-inset ring-indigo-500/20">
{{ $t('members.detail.orders.subscriptions.active', { count: +active }) }}
</span>
</div>
Expand Down Expand Up @@ -66,9 +66,7 @@ import { SUBSCRIPTION_UNIT_COST_IN_EUR, Subscription } from '@/services/api/memb
import SvgIcon from '@jamescoyle/vue-icon';
import { mdiPlus } from '@mdi/js';
import dayjs from 'dayjs';
import LocalizedFormat from 'dayjs/plugin/localizedFormat.js';
import { PropType } from 'vue';
dayjs.extend(LocalizedFormat);
defineProps({
subscriptions: {
Expand Down
Loading

0 comments on commit 040d0e3

Please sign in to comment.