Ver Fonte

working on selector.

Tomi Cvetic há 4 anos atrás
pai
commit
bafc06f2c2

+ 1 - 1
frontend/pages/admin/file/index.tsx

@@ -13,7 +13,7 @@ const AdminFile: FunctionComponent<{ item: Partial<File>; className?: string }>
   return (
     <div className={className}>
       <div className='admin-file-title'>
-        <a href={`/${item.path}`}>
+        <a href={`/${item.path}`} download={item.filename}>
           <FontAwesomeIcon icon={faLink} height={14} />
           {' ' + item.filename}
         </a>

+ 18 - 3
frontend/src/gql/index.tsx

@@ -4706,7 +4706,15 @@ export type TrainingsQueryVariables = {
 
 export type TrainingsQuery = { trainings: Array<DisplayTrainingFragment> };
 
-export type TrainingTypesQueryVariables = {};
+export type TrainingTypesQueryVariables = {
+  where?: Maybe<TrainingTypeWhereInput>,
+  orderBy?: Maybe<TrainingTypeOrderByInput>,
+  skip?: Maybe<Scalars['Int']>,
+  after?: Maybe<Scalars['String']>,
+  before?: Maybe<Scalars['String']>,
+  first?: Maybe<Scalars['Int']>,
+  last?: Maybe<Scalars['Int']>
+};
 
 
 export type TrainingTypesQuery = { trainingTypes: Array<Pick<TrainingType, 'id' | 'name' | 'description'>> };
@@ -5490,8 +5498,8 @@ export type TrainingsQueryHookResult = ReturnType<typeof useTrainingsQuery>;
 export type TrainingsLazyQueryHookResult = ReturnType<typeof useTrainingsLazyQuery>;
 export type TrainingsQueryResult = ApolloReactCommon.QueryResult<TrainingsQuery, TrainingsQueryVariables>;
 export const TrainingTypesDocument = gql`
-    query trainingTypes {
-  trainingTypes {
+    query trainingTypes($where: TrainingTypeWhereInput, $orderBy: TrainingTypeOrderByInput, $skip: Int, $after: String, $before: String, $first: Int, $last: Int) {
+  trainingTypes(where: $where, orderBy: $orderBy, skip: $skip, after: $after, before: $before, first: $first, last: $last) {
     id
     name
     description
@@ -5511,6 +5519,13 @@ export const TrainingTypesDocument = gql`
  * @example
  * const { data, loading, error } = useTrainingTypesQuery({
  *   variables: {
+ *      where: // value for 'where'
+ *      orderBy: // value for 'orderBy'
+ *      skip: // value for 'skip'
+ *      after: // value for 'after'
+ *      before: // value for 'before'
+ *      first: // value for 'first'
+ *      last: // value for 'last'
  *   },
  * });
  */

+ 1 - 1
frontend/src/training/components/EditTraining.tsx

@@ -8,7 +8,7 @@ import BlockList from './BlockList'
 import theme from '../../styles/theme'
 
 const EditTraining = ({ training }: { training?: Partial<Training> }) => {
-  const { values, onChange } = useForm(training || ({} as Partial<Training>))
+  const { values, onChange } = useForm(training || {})
   const [createTraining, createData] = useCreateTrainingMutation()
   const [updateTraining, updateData] = useUpdateTrainingMutation()
 

+ 127 - 0
frontend/src/training/components/Selector.tsx

@@ -0,0 +1,127 @@
+import { useTrainingTypesQuery, TrainingType } from '../../gql'
+import AddTrainingType from './AddTrainingType'
+import { useState, useEffect } from 'react'
+import { Modal } from '../../modal'
+import Dropdown from '../../dropdown/components/Dropdown'
+import { QueryHookOptions, QueryResult } from '@apollo/client'
+import { TextInput } from '../../form'
+
+interface ISelector<TQueryData, TQueryVariables> {
+  name: string
+  value: any
+  onChange: GenericEventHandler
+  callback: (selectedIndex: number) => void
+  query: (
+    baseOptions?: QueryHookOptions<TQueryData, { where: { OR: { [key: string]: string }[] } }>
+  ) => QueryResult<TQueryData, TQueryVariables>
+  searchKeys?: (keyof TQueryData)[]
+  dataKey: keyof TQueryData
+  selectedKey: keyof TQueryData
+  className?: string
+}
+
+/**
+ * The selector allows to select an item from a list and offers tools to add, edit or remove items.
+ * @param param0
+ */
+const Selector = <
+  TQueryData extends { [dataKey: string]: any[] },
+  TQueryVariables extends Record<string, any>
+>({
+  name,
+  value,
+  onChange,
+  query,
+  searchKeys,
+  dataKey,
+  className,
+}: ISelector<TQueryData, TQueryVariables>) => {
+  const [searchTerm, setSearchTerm] = useState('')
+  const searchVariables =
+    searchKeys && searchTerm !== ''
+      ? { variables: { where: { OR: searchKeys?.map((key) => ({ [key]: searchTerm })) } } }
+      : {}
+  const { data, error, loading } = query(searchVariables)
+
+  useEffect(() => {
+    setTimeout(() => console.log('debouonced.'), 300)
+  }, [searchTerm])
+
+  return (
+    <div className={className}>
+      <TextInput
+        name='search'
+        type='search'
+        value={searchTerm}
+        onChange={(event) => setSearchTerm(event.target.vale)}
+      />
+      <select
+        id={name}
+        name={name}
+        value={value}
+        onChange={(event) => {
+          const changeEvent: CustomChangeEvent = {
+            target: {
+              type: 'custom',
+              value: { id: event.target.value },
+              name,
+            },
+          }
+          onChange(changeEvent)
+        }}
+      >
+        {loading && 'loading training types...'}
+        {error && 'error loading training types'}
+        {data &&
+          data[dataKey].map((item) => (
+            <option key={item.id} value={item.id}>
+              {item.name}
+            </option>
+          ))}
+      </select>
+      <button
+        type='button'
+        onClick={(event) => {
+          setModalState(true)
+        }}
+      >
+        Add type
+      </button>
+      <Modal state={[modalState, setModalState]}>
+        <AddTrainingType
+          onSuccess={(result) => {
+            setModalState(false)
+            if (result.data) {
+              onChange({
+                target: {
+                  type: 'custom',
+                  value: { id: result.data.createTrainingType.id },
+                  name,
+                },
+              })
+            }
+          }}
+        />
+      </Modal>
+
+      <style jsx>{`
+        div {
+          display: flex;
+          align-items: center;
+        }
+
+        label,
+        select,
+        button {
+          display: inline-block;
+          width: auto;
+        }
+        select {
+          flex-grow: 1;
+          margin: 0 0.6em;
+        }
+      `}</style>
+    </div>
+  )
+}
+export default Selector

+ 10 - 3
frontend/src/training/components/TrainingTypeSelector.tsx

@@ -1,8 +1,12 @@
-import { useTrainingTypesQuery, TrainingType } from '../../gql'
+import {
+  useTrainingTypesQuery,
+  TrainingType,
+  TrainingTypesQuery,
+  TrainingTypesQueryVariables,
+} from '../../gql'
 import AddTrainingType from './AddTrainingType'
 import { useState, useEffect } from 'react'
 import { Modal } from '../../modal'
-import Select from '../../form/components/Select'
 
 interface ITrainingTypeSelector {
   value?: TrainingType
@@ -20,7 +24,10 @@ const TrainingTypeSelector = ({
   className = 'training-type',
 }: ITrainingTypeSelector) => {
   const [modalState, setModalState] = useState(false)
-  const trainingTypes = useTrainingTypesQuery()
+  const myQuery = {
+    variables: { where: { OR: [{ description_contains: 'hi' }, { name_contains: 'hi' }] } },
+  }
+  const trainingTypes = useTrainingTypesQuery(myQuery)
   const id = value?.id ?? ''
 
   useEffect(() => {

+ 18 - 2
frontend/src/training/training.graphql

@@ -56,8 +56,24 @@ query trainings(
   }
 }
 
-query trainingTypes {
-  trainingTypes {
+query trainingTypes(
+  $where: TrainingTypeWhereInput
+  $orderBy: TrainingTypeOrderByInput
+  $skip: Int
+  $after: String
+  $before: String
+  $first: Int
+  $last: Int
+) {
+  trainingTypes(
+    where: $where
+    orderBy: $orderBy
+    skip: $skip
+    after: $after
+    before: $before
+    first: $first
+    last: $last
+  ) {
     id
     name
     description