Просмотр исходного кода

Feat: Mobile - add plus sign for quick tickt creation, and dummy search input

Vladimir Sheremet 2 лет назад
Родитель
Сommit
e384e1d360

+ 11 - 0
.storybook/config/preview-body.html

@@ -0,0 +1,11 @@
+<script>
+  setTimeout(() => {
+    const body = document.body
+    body.classList.add('text-white')
+    body.classList.add('bg-black')
+
+    const root = document.documentElement
+
+    root.setAttribute('dir', 'ltr')
+  }, 100)
+</script>

+ 3 - 3
app/frontend/apps/mobile/components/CommonSectionMenu/CommonSectionMenu.vue

@@ -24,8 +24,8 @@ const clickOnAction = (event: MouseEvent) => {
 </script>
 
 <template>
-  <div class="flex flex-row justify-between">
-    <div class="ltr:pl-4 rtl:pr-4">
+  <div class="mb-2 flex flex-row justify-between">
+    <div class="text-white/80 ltr:pl-4 rtl:pr-4">
       <slot name="header">{{ i18n.t(headerTitle) }}</slot>
     </div>
     <div
@@ -37,7 +37,7 @@ const clickOnAction = (event: MouseEvent) => {
     </div>
   </div>
   <div
-    class="w-fill m-2 mb-6 flex flex-col rounded-xl bg-gray-500 px-2 py-1 text-white"
+    class="w-fill mb-6 flex flex-col rounded-xl bg-gray-500 px-2 py-1 text-white"
   >
     <slot>
       <template v-for="(item, idx) in items" :key="idx">

+ 25 - 3
app/frontend/apps/mobile/components/CommonSectionMenu/CommonSectionMenuLink.vue

@@ -1,19 +1,32 @@
 <!-- Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/ -->
 
 <script setup lang="ts">
+import { computed, type HTMLAttributes } from 'vue'
+import { type Props as IconProps } from '@shared/components/CommonIcon/CommonIcon.vue'
 import useLocaleStore from '@shared/stores/locale'
 
 export interface Props {
   title?: string
   link?: string
-  icon?: string
+  icon?: string | (IconProps & HTMLAttributes)
+  iconBg?: string
   // TODO maybe change the name based on the usage
   information?: string
 }
 
-defineProps<Props>()
+const props = defineProps<Props>()
 
 const locale = useLocaleStore()
+
+const iconProps = computed<IconProps | null>(() => {
+  if (!props.icon) return null
+
+  if (typeof props.icon === 'string') {
+    return { name: props.icon }
+  }
+
+  return props.icon
+})
 </script>
 
 <template>
@@ -28,7 +41,16 @@ const locale = useLocaleStore()
       class="flex items-center justify-between border-b border-gray-300 last:border-0"
     >
       <div class="flex min-h-[54px] items-center">
-        <CommonIcon v-if="icon" :name="icon" class="mr-2" />
+        <div
+          v-if="iconProps"
+          class="flex h-8 w-8 items-center justify-center ltr:mr-2 rtl:ml-2"
+          data-test-id="wrapper-icon"
+          :class="{
+            [`rounded-lg ${iconBg}`]: iconBg,
+          }"
+        >
+          <CommonIcon v-bind="iconProps" />
+        </div>
         <slot>{{ i18n.t(title) }}</slot>
       </div>
 

+ 27 - 0
app/frontend/apps/mobile/components/CommonSectionMenu/__tests__/CommonSectionMenuLink.spec.ts

@@ -34,6 +34,33 @@ describe('rendering item for section', () => {
     expect(view.getIconByName('home')).toBeInTheDocument()
   })
 
+  it('has an icon with a background', () => {
+    const view = renderMenuItem({
+      link: '/',
+      iconBg: 'bg-red',
+      icon: 'home',
+    })
+
+    const icon = view.getByTestId('wrapper-icon')
+
+    expect(icon).toHaveClass('bg-red')
+    expect(icon).toHaveClass('rounded-lg')
+  })
+
+  it('accepts icon as object', () => {
+    const view = renderMenuItem({
+      link: '/',
+      icon: { name: 'home', fixedSize: { width: 40, height: 40 } },
+    })
+
+    const icon = view.getIconByName('home')
+
+    expect(icon).toBeInTheDocument()
+
+    expect(icon).toHaveAttribute('width', '40')
+    expect(icon).toHaveAttribute('height', '40')
+  })
+
   it("draws information, if it's provided", () => {
     const view = renderMenuItem({
       link: '/',

+ 2 - 2
app/frontend/apps/mobile/components/CommonSectionMenu/types.ts

@@ -2,7 +2,7 @@
 
 import { type Props as LinkProps } from './CommonSectionMenuLink.vue'
 
-export type MenuItem = {
+export interface MenuItem extends LinkProps {
   type: 'link'
   onClick?(event: MouseEvent): void
-} & LinkProps
+}

+ 1 - 1
app/frontend/apps/mobile/components/layout/LayoutBottomNavigation.vue

@@ -10,7 +10,7 @@ const { user } = storeToRefs(useSessionStore())
 
 <template>
   <footer
-    class="fixed bottom-0 z-10 flex h-14 w-full items-center border-t bg-black/30 text-center backdrop-blur-lg"
+    class="fixed bottom-0 z-10 flex h-14 w-full items-center bg-gray-light text-center backdrop-blur-lg"
   >
     <CommonLink
       link="/"

+ 1 - 1
app/frontend/apps/mobile/form/theme/global/getCoreClasses.ts

@@ -63,7 +63,7 @@ const getCoreClasses: FormThemeExtension = (classes: FormThemeClasses) => {
     text: addFloatingLabel(classes.text),
     email: addFloatingLabel(classes.email),
     number: addFloatingLabel(classes.number),
-    search: addFloatingLabel(classes.search),
+    search: { inner: 'flex', wrapper: 'px-3' },
     tel: addFloatingLabel(classes.tel),
     time: addFloatingLabel(classes.time),
     date: addDateLabel(classes.date),

+ 2 - 0
app/frontend/apps/mobile/main.ts

@@ -61,6 +61,8 @@ export default async function mountApp(): Promise<void> {
     enumerable: true,
     get: () => unref(config),
   })
+  // eslint-disable-next-line no-underscore-dangle
+  app.config.globalProperties.__ = window.__
 
   initializeForm(app)
 

+ 43 - 37
app/frontend/apps/mobile/modules/home/views/Home.vue

@@ -1,16 +1,33 @@
 <!-- Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/ -->
 
 <script setup lang="ts">
-import { useRouter } from 'vue-router'
-import useAuthenticationStore from '@shared/stores/authentication'
-import { useNotifications } from '@shared/components/CommonNotifications'
 import { MenuItem } from '@mobile/components/CommonSectionMenu'
 import CommonSectionMenu from '@mobile/components/CommonSectionMenu/CommonSectionMenu.vue'
+import CommonInputSearch from '@shared/components/CommonInputSearch/CommonInputSearch.vue'
 
+const IS_DEV = import.meta.env.DEV
+
+// TODO all menus should be generated on back-end
 const menu: MenuItem[] = [
-  { type: 'link', link: '/tickets', title: __('All Tickets') },
-  { type: 'link', link: '/', title: __('Knowledge Base') },
-  { type: 'link', link: '/', title: __('Chat'), information: '1' },
+  {
+    type: 'link',
+    link: '/tickets',
+    title: __('All Tickets'),
+    icon: { name: 'stack', size: 'base' },
+    iconBg: 'bg-pink',
+  },
+  // cannot inline import.meta here, Vite fails
+  ...(IS_DEV
+    ? [
+        {
+          type: 'link' as const,
+          link: '/playground',
+          title: 'Playground',
+          icon: { name: 'cog', size: 'small' as const },
+          iconBg: 'bg-orange',
+        },
+      ]
+    : []),
 ]
 
 const ticketOverview: MenuItem[] = [
@@ -40,44 +57,33 @@ const ticketOverview: MenuItem[] = [
   },
 ]
 
-const { clearAllNotifications } = useNotifications()
-const authentication = useAuthenticationStore()
-const router = useRouter()
-
-const logoutMenu: MenuItem[] = [
-  {
-    type: 'link',
-    onClick() {
-      clearAllNotifications()
-      authentication.logout().then(() => {
-        router.push('/login')
-      })
-    },
-    title: __('Logout'),
-  },
-]
-
-const testingMenu: MenuItem[] = [
-  {
-    type: 'link',
-    link: '/playground',
-    title: 'Playground',
-  },
-]
+const openSearchDialog = () => {
+  console.log('open dialog')
+}
 </script>
 
 <template>
-  <div class="pt-10">
-    <div class="flex w-full items-center justify-center text-3xl font-bold">
+  <div class="p-4">
+    <div class="my-6 flex justify-end ltr:mr-4 rtl:ml-4">
+      <CommonLink link="/#ticket/create">
+        <CommonIcon name="plus" size="small" />
+      </CommonLink>
+    </div>
+    <div
+      class="mb-5 flex w-full items-center justify-center text-4xl font-bold"
+    >
       {{ i18n.t('Home') }}
     </div>
-    <CommonSectionMenu :items="testingMenu" />
-    <CommonSectionMenu :items="menu" action-title="Edit" />
+    <CommonInputSearch
+      wrapper-class="mb-4"
+      no-border
+      @click="openSearchDialog"
+    />
+    <CommonSectionMenu :items="menu" />
     <CommonSectionMenu
       :items="ticketOverview"
-      header-title="Ticket overviews"
-      action-title="Edit"
+      :header-title="__('Ticket Overview')"
+      :action-title="__('Edit')"
     />
-    <CommonSectionMenu :items="logoutMenu" />
   </div>
 </template>

+ 8 - 0
app/frontend/apps/mobile/modules/playground/views/PlaygroundOverview.vue

@@ -15,6 +15,14 @@ const linkSchemaRaw = [
       link: '/tickets',
     },
   },
+  {
+    type: 'search',
+    name: 'search',
+    // label: 'Date_Input',
+    props: {
+      link: '/tickets',
+    },
+  },
   {
     type: 'select',
     name: 'select',

Некоторые файлы не были показаны из-за большого количества измененных файлов