Browse Source

converted invoice card to a generic component called item card

master
kj1352 4 years ago
parent
commit
1f77cf4b1e
6 changed files with 137 additions and 180 deletions
  1. +0
    -130
      src/components/invoice-card/invoice.tsx
  2. +4
    -3
      src/components/item-card/itemCard.module.scss
  3. +102
    -0
      src/components/item-card/itemCard.tsx
  4. +0
    -0
      src/components/transaction-card/transaction.module.scss
  5. +0
    -10
      src/components/transaction-card/transaction.tsx
  6. +31
    -37
      src/pages/accounts/accounts.tsx

+ 0
- 130
src/components/invoice-card/invoice.tsx View File

@@ -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>
}

src/components/invoice-card/invoice.module.scss → src/components/item-card/itemCard.module.scss View File

@@ -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 {

+ 102
- 0
src/components/item-card/itemCard.tsx View File

@@ -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> */}

+ 0
- 0
src/components/transaction-card/transaction.module.scss View File


+ 0
- 10
src/components/transaction-card/transaction.tsx View File

@@ -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>
}

+ 31
- 37
src/pages/accounts/accounts.tsx View File

@@ -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>
); );


Loading…
Cancel
Save