You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

page.tsx 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. "use client";
  2. import { useState } from 'react';
  3. import PageTitle from '@/components/ui/PageTitle';
  4. import { Typography, Input, Form, Select, Switch, Flex, Row, Col } from 'antd';
  5. import Link from 'next/link';
  6. import type { PaymentType } from '@/types/payment';
  7. import { useQuery } from '@tanstack/react-query';
  8. import { getPaymentType } from '@/app/api/general/paymentService';
  9. import AltLayout from '@/components/layout/AltLayout';
  10. import PrimaryButton from '@/components/ui/PrimaryButton';
  11. import IconCard from '@/components/ui/IconCard';
  12. import LoadingScreen from '@/components/layout/LoadingScreen';
  13. const { Text } = Typography;
  14. const CreatePersona: React.FC = () => {
  15. // Form states
  16. const [selectedPaymentID, setSelectedPaymentID] = useState<number | undefined>();
  17. const [companyName, setCompanyName] = useState('');
  18. const [cardNumber, setCardNumber] = useState('');
  19. const [isDefault, setIsDefault] = useState(false);
  20. const [cvc, setCvc] = useState('');
  21. // Fetch payment types using React Query
  22. const { data: paymentType, isLoading } = useQuery<PaymentType[] | undefined>({
  23. queryKey: ['getPaymentType'],
  24. queryFn: getPaymentType
  25. });
  26. // Show loading state while fetching data
  27. if (isLoading) return <LoadingScreen/>
  28. return (
  29. <AltLayout header={<PageTitle backButton={true}>PAYMENT</PageTitle>}>
  30. <Row className='!bg-white'>
  31. <Col span={24} className='!p-4'>
  32. {/* Section intro */}
  33. <Flex vertical gap={10} className='!mb-8'>
  34. <Text className='!font-semibold !text-xs !text-gray-400'>Enter your payment details <br />
  35. <Text italic className='!text-xs'>
  36. By continuing you agree to our <Link href="/">Terms</Link>
  37. </Text>
  38. </Text>
  39. </Flex>
  40. {/* Payment type selection */}
  41. <Flex wrap gap={8}>
  42. {paymentType?.map(({ id, description, icon_id }) => <IconCard key={id} active={selectedPaymentID === id} iconName={icon_id} text={description} handleClick={() => { setSelectedPaymentID(id)}} />)}
  43. </Flex>
  44. {/* Payment form */}
  45. <Row>
  46. <Col span={24} className="px-2 mt-4">
  47. <Form layout="vertical">
  48. <Row>
  49. <Col span={24}>
  50. {/* Company Name */}
  51. <Form.Item label={<Text className='!italic !text-xs !font-semibold'>Company Name</Text>}>
  52. <Input
  53. placeholder="Company Name"
  54. value={companyName}
  55. onChange={(e) => setCompanyName(e.target.value)}
  56. />
  57. </Form.Item>
  58. {/* Card Number with formatting */}
  59. <Form.Item label={<Text className='!italic !text-xs !font-semibold'>Card Number</Text>}>
  60. <Input
  61. value={cardNumber}
  62. onChange={(e) => {
  63. const rawValue = e.target.value.replace(/\D/g, '').slice(0, 16);
  64. const formattedValue = rawValue.replace(/(.{4})/g, '$1 ').trim();
  65. setCardNumber(formattedValue);
  66. }}
  67. />
  68. </Form.Item>
  69. {/* Expiration Month & Year */}
  70. <Flex gap={10}>
  71. <Form.Item label={<Text className='!italic !text-xs !font-semibold'>Exp Month</Text>} className="w-full">
  72. <Select
  73. allowClear
  74. placeholder="Please select"
  75. options={Array.from({ length: 12 }, (_, i) => {
  76. const month = String(i + 1).padStart(2, '0');
  77. return { label: month, value: month };
  78. })}
  79. />
  80. </Form.Item>
  81. <Form.Item label={<Text className='!italic !text-xs !font-semibold'>Exp Year</Text>} className="w-full">
  82. <Select
  83. allowClear
  84. placeholder="Please select"
  85. options={Array.from({ length: 10 }, (_, i) => {
  86. const year = new Date().getFullYear() + i;
  87. return { label: String(year), value: String(year) };
  88. })}
  89. />
  90. </Form.Item>
  91. </Flex>
  92. {/* CVC with note */}
  93. <Form.Item label={<Text className='!italic !text-xs !font-semibold'>CVC</Text>}>
  94. <Flex gap={12}>
  95. <Input
  96. placeholder="123"
  97. className='!max-w-[50px]'
  98. value={cvc}
  99. onChange={(e) => {
  100. const rawValue = e.target.value.replace(/\D/g, '').slice(0, 4);
  101. setCvc(rawValue);
  102. }}
  103. />
  104. <Text className='!text-gray-300 !max-w-[160px]' style={{ fontSize: 10 }}>
  105. 3 or 4 digits usually found on the signature strip
  106. </Text>
  107. </Flex>
  108. </Form.Item>
  109. {/* Default payment switch */}
  110. <Form.Item>
  111. <Flex gap={4}>
  112. <Switch checked={isDefault} onChange={setIsDefault} />
  113. <Text className='!text-xs font-semibold'>SET AS DEFAULT</Text>
  114. </Flex>
  115. </Form.Item>
  116. </Col>
  117. </Row>
  118. {/* Submit Button */}
  119. <PrimaryButton customStyle='!w-full !py-3'>
  120. CONFIRM
  121. </PrimaryButton>
  122. </Form>
  123. </Col>
  124. </Row>
  125. </Col>
  126. </Row>
  127. </AltLayout>
  128. );
  129. };
  130. export default CreatePersona;