Skip to content

Commit

Permalink
Merge pull request #2673 from CAFECA-IO/feature/certificate_upload
Browse files Browse the repository at this point in the history
Feature/certificate upload
  • Loading branch information
Luphia authored Sep 26, 2024
2 parents d3862bb + 180301c commit 0e31478
Show file tree
Hide file tree
Showing 20 changed files with 816 additions and 89 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "iSunFA",
"version": "0.8.2+13",
"version": "0.8.2+14",
"private": false,
"scripts": {
"dev": "next dev",
Expand Down
103 changes: 103 additions & 0 deletions public/elements/siri.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions src/components/ai_analyzer/ai_analyzer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Image from 'next/image';

interface AIAnalyzerProps {}

const AIAnalyzer: React.FC<AIAnalyzerProps> = () => {
return (
<div className="mt-4 flex items-center justify-between overflow-hidden rounded-md bg-surface-brand-primary-moderate px-4 py-2">
<div className="relative h-20 w-20">
<Image
src="/elements/siri.svg"
alt="AI"
width={180}
height={190}
className="absolute left-1/2 top-14 max-w-180px -translate-x-1/2 -translate-y-1/2 object-cover"
/>
</div>
<p className="text-lg font-medium">
Please select the certificates for AI to generate the voucher for you
</p>
</div>
);
};

export default AIAnalyzer;
3 changes: 3 additions & 0 deletions src/components/certificate/certificate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import CertificateGrid from './certificate_grid';
interface CertificateProps {
data: ICertificateUI[]; // Info: (20240923 - tzuhan) 項目列表
viewType: VIEW_TYPES; // Info: (20240923 - tzuhan) 顯示模式
activeTab: number; // Info: (20240926 - tzuhan) 活躍的 Tab
activeSelection: boolean; // Info: (20240923 - tzuhan) 是否處於選擇狀態
handleSelect: (ids: number[], isSelected: boolean) => void;
isSelectedAll: boolean;
Expand All @@ -20,6 +21,7 @@ interface CertificateProps {
const Certificate: React.FC<CertificateProps> = ({
data,
viewType,
activeTab,
activeSelection,
handleSelect,
isSelectedAll,
Expand All @@ -46,6 +48,7 @@ const Certificate: React.FC<CertificateProps> = ({
{viewType === VIEW_TYPES.GRID && (
<CertificateGrid
data={data.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage)}
activeTab={activeTab}
activeSelection={activeSelection}
handleSelect={handleSelect}
onDownload={onDownload}
Expand Down
28 changes: 8 additions & 20 deletions src/components/certificate/certificate_edit_modal.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { CERTIFICATE_TYPES, ICertificateUI, INVOICE_TYPES } from '@/interfaces/certificate';
import Image from 'next/image';
import React, { useState } from 'react';
import NumericInput from '@/components/numeric_input/numeric_input';
import { RxCross1 } from 'react-icons/rx';
import useOuterClick from '@/lib/hooks/use_outer_click';
import { useTranslation } from 'react-i18next';
import { IoIosArrowDown } from 'react-icons/io';
import useOuterClick from '@/lib/hooks/use_outer_click';
import NumericInput from '@/components/numeric_input/numeric_input';
import Toggle from '@/components/toggle/toggle';
import Modal from '@/components/modal/modal';
import { Button } from '@/components/button/button';
import { CERTIFICATE_TYPES, ICertificateUI, INVOICE_TYPES } from '@/interfaces/certificate';

interface CertificateEditModalProps {
isOpen: boolean;
Expand Down Expand Up @@ -74,20 +74,8 @@ const CertificateEditModal: React.FC<CertificateEditModalProps> = ({
if (!isOpen) return null;

return (
<div
className="fixed inset-0 z-70 flex items-center justify-center bg-black/50"
onClick={onClose}
>
<div className="relative flex max-h-450px w-90vw max-w-800px flex-col rounded-sm bg-surface-neutral-surface-lv2 p-20px md:max-h-90vh">
{/* Info: (20240924 - tzuhan) 關閉按鈕 */}
<button
type="button"
className="absolute right-4 top-4 text-checkbox-text-primary"
onClick={onClose}
>
<RxCross1 size={32} />
</button>

<Modal isOpen={isOpen} onClose={onClose}>
<>
{/* Info: (20240924 - tzuhan) 模態框標題 */}
<h2 className="mb-4 flex justify-center gap-2 text-xl font-semibold">
{certificate.invoiceName}
Expand Down Expand Up @@ -324,8 +312,8 @@ const CertificateEditModal: React.FC<CertificateEditModalProps> = ({
</div>
</div>
</div>
</div>
</div>
</>
</Modal>
);
};

Expand Down
33 changes: 20 additions & 13 deletions src/components/certificate/certificate_grid.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from 'react';
import CertificateThumbnail from '@/components/certificate/certificate_thumbnail'; // 引入 CertificateThumbnail 組件
import { ICertificateUI } from '@/interfaces/certificate';
import CertificateThumbnail from '@/components/certificate/certificate_thumbnail';
import FloatingUploadPopup from '@/components/floating_upload_popup/floating_upload_popup';

interface CertificateGridProps {
data: ICertificateUI[]; // Info: (20240923 - tzuhan) 項目列表
activeSelection: boolean; // Info: (20240923 - tzuhan) 是否處於選擇狀態
activeTab: number;
handleSelect: (ids: number[], isSelected: boolean) => void;
onRemove: (id: number) => void;
onDownload: (id: number) => void;
Expand All @@ -14,24 +16,29 @@ interface CertificateGridProps {
const CertificateGrid: React.FC<CertificateGridProps> = ({
data,
activeSelection,
activeTab,
handleSelect,
onRemove,
onDownload,
onEdit,
}) => {
return (
<div className="grid grid-cols-dynamic-fit place-items-center gap-4">
{data.map((certificate) => (
<CertificateThumbnail
data={certificate}
activeSelection={activeSelection}
handleSelect={handleSelect}
onRemove={onRemove}
onDownload={onDownload}
onEdit={onEdit}
/>
))}
</div>
<>
<div className="grid grid-cols-dynamic-fit place-items-center gap-4">
{data.map((certificate) => (
<CertificateThumbnail
data={certificate}
activeSelection={activeSelection}
handleSelect={handleSelect}
onRemove={onRemove}
onDownload={onDownload}
onEdit={onEdit}
/>
))}
</div>
{/* Info: (20240926- tzuhan) Floating Upload Popup */}
{activeTab === 0 && <FloatingUploadPopup />}
</>
);
};

Expand Down
66 changes: 66 additions & 0 deletions src/components/certificate/certificate_selection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import Image from 'next/image';
import { Button } from '@/components/button/button';
import { AiOutlineLeft, AiOutlineRight } from 'react-icons/ai';
import { FaPlus } from 'react-icons/fa6';
import { ICertificate } from '@/interfaces/certificate';

interface CertificateSelectionProps {
selectedCertificates: ICertificate[];
setOpenModal: (open: boolean) => void;
}

const CertificateSelection: React.FC<CertificateSelectionProps> = ({
selectedCertificates,
setOpenModal,
}: CertificateSelectionProps) => {
return (
<div className="my-8 w-full flex-col items-center">
<div className="flex h-56 w-full flex-col items-start justify-start rounded-md border border-stroke-neutral-quaternary px-8 pt-6 shadow-inset-lg">
<div className="flex space-x-4 overflow-x-auto">
{selectedCertificates.map((certificate) => (
<div key={certificate.id} className="flex flex-col items-center">
<Image src={certificate.thumbnailUrl} alt="AI" width={80} height={80} />
<p className="text-sm font-semibold">{certificate.invoiceName}</p>
</div>
))}
<div>
<button
type="button"
className="mx-4 my-2 flex h-140px w-80px items-center justify-center rounded-xs border border-dashed border-stroke-neutral-tertiary p-2 text-white"
onClick={() => setOpenModal(true)}
>
<FaPlus size={24} className="text-stroke-neutral-tertiary" />
</button>
</div>
</div>
</div>
<div className="mt-2 w-full text-center">
<p className="text-text-neutral-tertiary">
Uploaded {selectedCertificates.length} certificates
</p>
<div className="mt-2 flex items-center justify-center space-x-2">
<Button
type="button"
onClick={() => {}}
variant="secondaryOutline"
disabled={selectedCertificates.length === 0}
className="h-40px w-40px p-0"
>
<AiOutlineLeft size={16} />
</Button>
<Button
type="button"
onClick={() => {}}
variant="secondaryOutline"
disabled={selectedCertificates.length === 0}
className="h-40px w-40px p-0"
>
<AiOutlineRight size={16} />
</Button>
</div>
</div>
</div>
);
};

export default CertificateSelection;
Loading

0 comments on commit 0e31478

Please sign in to comment.