| @@ -1,130 +0,0 @@ | |||||
| import React, { useState } from 'react'; | |||||
| import styles from './invoice.module.scss'; | |||||
| import { ReactComponent as ChevronBack } from 'ionicons/dist/svg/chevron-back.svg'; | |||||
| import { format } from 'date-fns'; | |||||
| import { IonButton, IonDatetime, IonInput } from '@ionic/react'; | |||||
| type OwnProps = { | |||||
| invoice: { | |||||
| id: string, | |||||
| date: string, | |||||
| status: string, | |||||
| dateOfPayment?: string, | |||||
| referenceNumber?: string, | |||||
| }, | |||||
| client: { | |||||
| name: string, | |||||
| logo: string, | |||||
| project: { | |||||
| name: string, | |||||
| contract: { | |||||
| name: string, | |||||
| amount: string, | |||||
| }, | |||||
| } | |||||
| } | |||||
| } | |||||
| export const InvoiceCard: React.FC<OwnProps> = (props) => { | |||||
| const [showDetails, setShowDetails] = useState<boolean>(false); | |||||
| const [formInputs, setFormInputs] = useState<{ | |||||
| dateOfPayment: string, | |||||
| referenceNumber: string, | |||||
| }>({ | |||||
| dateOfPayment: props.invoice.dateOfPayment ? props.invoice.dateOfPayment.toString() : '', | |||||
| referenceNumber: props.invoice.referenceNumber ? props.invoice.referenceNumber : '', | |||||
| }); | |||||
| let statusClass = ''; | |||||
| switch (props.invoice.status) { | |||||
| case 'due': statusClass = styles.due; break; | |||||
| case 'over due': statusClass = styles.overDue; break; | |||||
| case 'paid': statusClass = styles.paid; break; | |||||
| case 'cancelled': statusClass = styles.cancelled; break; | |||||
| default: break; | |||||
| } | |||||
| return <div> | |||||
| <section className={styles.card} onClick={() => setShowDetails(true)}> | |||||
| <figure> | |||||
| <img src={props.client.logo} alt="logo" /> | |||||
| </figure> | |||||
| <div className={styles.contentHolder}> | |||||
| <h6> Invoice ID: {props.invoice.id} </h6> | |||||
| <h2> {props.client.project.contract.amount} </h2> | |||||
| <p> {props.client.project.contract.name} </p> | |||||
| </div> | |||||
| <div className={styles.status}> | |||||
| <span className={statusClass}> {props.invoice.status} </span> | |||||
| </div> | |||||
| </section> | |||||
| { showDetails && <div className={styles.backdrop}> | |||||
| <section className={styles.cardDetails}> | |||||
| <header> | |||||
| <IonButton onClick={() => setShowDetails(false)} fill={'clear'} size={'small'}> <ChevronBack /> </IonButton> | |||||
| <h4> Pending Invoice </h4> | |||||
| </header> | |||||
| <ul> | |||||
| <li> | |||||
| <label> Invoice ID </label> | |||||
| <p> {props.invoice.id} </p> | |||||
| </li> | |||||
| <li> | |||||
| <label> Invoice Date </label> | |||||
| <p> {format(new Date(props.invoice.date), 'dd MMMM yyyy')} </p> | |||||
| </li> | |||||
| <li> | |||||
| <label> Client </label> | |||||
| <p> {props.client.name} </p> | |||||
| </li> | |||||
| <li> | |||||
| <label> Project </label> | |||||
| <p> {props.client.project.name} </p> | |||||
| </li> | |||||
| <li> | |||||
| <label> Contract </label> | |||||
| <p> {props.client.project.contract.name} </p> | |||||
| </li> | |||||
| <li> | |||||
| <label> Invoice Amount </label> | |||||
| <p> {props.client.project.contract.amount} </p> | |||||
| </li> | |||||
| </ul> | |||||
| <section className={styles.form}> | |||||
| <div className={styles.inputHolder}> | |||||
| <label> Payment Date </label> | |||||
| <IonDatetime value={formInputs.dateOfPayment} mode={'ios'} placeholder={'DD/MM/YYYY'} displayFormat={'DD/MM/YYYY'} | |||||
| onIonChange={(e) => setFormInputs({ | |||||
| dateOfPayment: e.detail.value? e.detail.value.toString() : '', | |||||
| referenceNumber: formInputs.referenceNumber, | |||||
| })}></IonDatetime> | |||||
| </div> | |||||
| <div className={styles.inputHolder}> | |||||
| <label> Reference No. </label> | |||||
| <IonInput placeholder={'Enter here'} value={formInputs.referenceNumber} | |||||
| onIonChange={(e) => setFormInputs({ | |||||
| dateOfPayment: formInputs.dateOfPayment, | |||||
| referenceNumber: e.detail.value? e.detail.value.toString() : '', | |||||
| })}></IonInput> | |||||
| </div> | |||||
| {(props.invoice.status !== 'cancelled' && props.invoice.status !== 'paid' || formInputs.dateOfPayment !== props.invoice.dateOfPayment || formInputs.dateOfPayment !== props.invoice.date) && <div className={styles.buttonsHolder}> | |||||
| <IonButton fill={'outline'} className={styles.cancel} shape={'round'}> Cancel Invoice </IonButton> | |||||
| <IonButton fill={'solid'} className={styles.approve + ' ' + (formInputs.dateOfPayment && formInputs.referenceNumber ? '' : styles.disabled)} shape={'round'} | |||||
| onClick={() => setShowDetails(false)}> Paid </IonButton> | |||||
| </div>} | |||||
| </section> | |||||
| </section> | |||||
| </div> } | |||||
| </div> | |||||
| } | |||||
| @@ -63,9 +63,10 @@ | |||||
| height: 7px; | height: 7px; | ||||
| border-radius: 50%; | border-radius: 50%; | ||||
| background-color: var(--grey); | background-color: var(--grey); | ||||
| margin-right: 5px; | |||||
| } | } | ||||
| &.due { | |||||
| &.warning { | |||||
| color: var(--warning); | color: var(--warning); | ||||
| &::before { | &::before { | ||||
| @@ -73,7 +74,7 @@ | |||||
| } | } | ||||
| } | } | ||||
| &.overDue { | |||||
| &.danger { | |||||
| color: var(--red); | color: var(--red); | ||||
| &::before { | &::before { | ||||
| @@ -81,7 +82,7 @@ | |||||
| } | } | ||||
| } | } | ||||
| &.paid { | |||||
| &.success { | |||||
| color: var(--teal); | color: var(--teal); | ||||
| &::before { | &::before { | ||||
| @@ -0,0 +1,102 @@ | |||||
| import React, { useState } from 'react'; | |||||
| import styles from './itemCard.module.scss'; | |||||
| import { ReactComponent as ChevronBack } from 'ionicons/dist/svg/chevron-back.svg'; | |||||
| import { IonButton } from '@ionic/react'; | |||||
| type OwnProps = { | |||||
| leftImage?: string, | |||||
| heading: { | |||||
| name: string, | |||||
| value: string | |||||
| }, | |||||
| value: string, | |||||
| description?: string, | |||||
| rightText?: { | |||||
| name: string, | |||||
| type: 'success' | 'danger' | 'warning' | undefined | |||||
| }, | |||||
| details?: Array<{ | |||||
| name: string, | |||||
| value: string | |||||
| }>, | |||||
| form?: JSX.Element | |||||
| } | |||||
| // Card - Image on the left, heading-value-description in the middle and status or any text on the right. eg: Pending invoice cards | |||||
| export const ItemCard: React.FC<OwnProps> = (props) => { | |||||
| const [showDetails, setShowDetails] = useState<boolean>(false); | |||||
| let statusClass = ''; | |||||
| if (props.rightText && props.rightText.type) { | |||||
| switch(props.rightText.type) { | |||||
| case 'success' : statusClass = styles.success; break; | |||||
| case 'danger' : statusClass = styles.danger; break; | |||||
| case 'warning' : statusClass = styles.warning; break; | |||||
| default: statusClass = ''; | |||||
| } | |||||
| } | |||||
| return <div> | |||||
| <section className={styles.card} onClick={() => setShowDetails(true)}> | |||||
| <figure> | |||||
| <img src={props.leftImage} /> | |||||
| </figure> | |||||
| <div className={styles.contentHolder}> | |||||
| <h6> { props.heading.name }: {props.heading.value} </h6> | |||||
| <h2> {props.value} </h2> | |||||
| <p> {props.description} </p> | |||||
| </div> | |||||
| { props.rightText && <div className={styles.status}> | |||||
| <span | |||||
| className={statusClass}> { props.rightText.name } </span> | |||||
| </div> } | |||||
| </section> | |||||
| { showDetails && props.details && <div className={styles.backdrop} onClick={(e: any) => { | |||||
| if (e.target.className.toString().includes('backdrop')) { | |||||
| setShowDetails(false); | |||||
| } | |||||
| }}> | |||||
| <section className={styles.cardDetails}> | |||||
| <header> | |||||
| <IonButton onClick={() => setShowDetails(false)} fill={'clear'} size={'small'}> <ChevronBack /> </IonButton> | |||||
| <h4> Pending Invoice </h4> | |||||
| </header> | |||||
| <ul> | |||||
| { props.details.map((detail, key) => { | |||||
| return <li key={key}> | |||||
| <label> { detail.name } </label> | |||||
| <p> { detail.value } </p> | |||||
| </li> | |||||
| }) } | |||||
| </ul> | |||||
| { props.form } | |||||
| </section> | |||||
| </div> } | |||||
| </div> | |||||
| } | |||||
| {/* <section className={styles.form}> | |||||
| <div className={styles.inputHolder}> | |||||
| <label> Payment Date </label> | |||||
| <IonDatetime mode={'ios'} placeholder={'DD/MM/YYYY'} displayFormat={'DD/MM/YYYY'}></IonDatetime> | |||||
| </div> | |||||
| <div className={styles.inputHolder}> | |||||
| <label> Reference No. </label> | |||||
| <IonInput placeholder={'Enter here'}></IonInput> | |||||
| </div> | |||||
| <div className={styles.buttonsHolder}> | |||||
| <IonButton fill={'outline'} className={styles.cancel} shape={'round'}> Cancel Invoice </IonButton> | |||||
| <IonButton fill={'solid'} className={styles.approve} shape={'round'} | |||||
| onClick={() => setShowDetails(false)}> Paid </IonButton> | |||||
| </div> | |||||
| </section> */} | |||||
| @@ -1,10 +0,0 @@ | |||||
| import React from 'react'; | |||||
| import styles from './invoice.module.scss'; | |||||
| import { format } from 'date-fns'; | |||||
| export const TransactionCard: React.FC = () => { | |||||
| return <div className={styles.card}> | |||||
| </div> | |||||
| } | |||||
| @@ -2,7 +2,8 @@ import { IonContent, IonPage } from '@ionic/react'; | |||||
| import { ReactComponent as CogIcon } from 'ionicons/dist/svg/cog-outline.svg'; | import { ReactComponent as CogIcon } from 'ionicons/dist/svg/cog-outline.svg'; | ||||
| import { ReactComponent as LineChartIcon } from 'ionicons/dist/svg/stats-chart.svg'; | import { ReactComponent as LineChartIcon } from 'ionicons/dist/svg/stats-chart.svg'; | ||||
| import styles from './accounts.module.scss'; | import styles from './accounts.module.scss'; | ||||
| import { InvoiceCard } from '../../components/invoice-card/invoice'; | |||||
| import { ItemCard } from '../../components/item-card/itemCard'; | |||||
| import { format } from 'date-fns'; | |||||
| const sampleInvoiceData = [{ | const sampleInvoiceData = [{ | ||||
| invoice: { | invoice: { | ||||
| @@ -102,46 +103,39 @@ const Accounts: React.FC = () => { | |||||
| </header> | </header> | ||||
| {sampleInvoiceData.map((invoice, key) => { | {sampleInvoiceData.map((invoice, key) => { | ||||
| return <InvoiceCard key={key} invoice={invoice.invoice} client={invoice.client} /> | |||||
| })} | |||||
| </div> | |||||
| <div className={styles.dashboardContainerSegment}> | |||||
| <header> | |||||
| <h5> Pending Invoices </h5> | |||||
| <a> See All </a> | |||||
| </header> | |||||
| {sampleInvoiceData.map((invoice, key) => { | |||||
| return <InvoiceCard key={key} invoice={invoice.invoice} client={invoice.client} /> | |||||
| })} | |||||
| </div> | |||||
| <div className={styles.dashboardContainerSegment}> | |||||
| <header> | |||||
| <h5> Pending Invoices </h5> | |||||
| <a> See All </a> | |||||
| </header> | |||||
| {sampleInvoiceData.map((invoice, key) => { | |||||
| return <InvoiceCard key={key} invoice={invoice.invoice} client={invoice.client} /> | |||||
| })} | |||||
| </div> | |||||
| <div className={styles.dashboardContainerSegment}> | |||||
| <header> | |||||
| <h5> Pending Invoices </h5> | |||||
| <a> See All </a> | |||||
| </header> | |||||
| {sampleInvoiceData.map((invoice, key) => { | |||||
| return <InvoiceCard key={key} invoice={invoice.invoice} client={invoice.client} /> | |||||
| return <ItemCard key={key} | |||||
| leftImage={invoice.client.logo} | |||||
| heading={{ name: 'Invoice ID', value: invoice.invoice.id }} | |||||
| value={invoice.client.project.contract.amount} | |||||
| description={invoice.client.project.contract.name} | |||||
| rightText={{ | |||||
| name: invoice.invoice.status, | |||||
| type: invoice.invoice.status === 'due' ? 'warning' : 'danger' | |||||
| }} | |||||
| details={[{ | |||||
| name: 'Invoice ID', | |||||
| value: invoice.invoice.id, | |||||
| }, { | |||||
| name: 'Invoice Date', | |||||
| value: format(new Date(invoice.invoice.date), 'dd MMMM yyyy') | |||||
| }, { | |||||
| name: 'Client', | |||||
| value: invoice.client.name | |||||
| }, { | |||||
| name: 'Project', | |||||
| value: invoice.client.project.name | |||||
| }, { | |||||
| name: 'Contract', | |||||
| value: invoice.client.project.contract.name | |||||
| }, { | |||||
| name: 'Invoice Amount', | |||||
| value: invoice.client.project.contract.amount | |||||
| }]} | |||||
| /> | |||||
| })} | })} | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </IonContent> | </IonContent> | ||||
| </IonPage> | </IonPage> | ||||
| ); | ); | ||||