瀏覽代碼

Full antd design 2

master
azri 3 天之前
父節點
當前提交
c900bdc4f9

+ 0
- 1
app/user/knowledge/create/page.tsx 查看文件

@@ -202,7 +202,6 @@ const CreatePersona: React.FC = () => {
202 202
                             </Col>
203 203
                         </Row>
204 204
 
205
-
206 205
                     </Form>
207 206
                 </Col>
208 207
             </Row>

+ 3
- 1
app/user/layout.tsx 查看文件

@@ -14,7 +14,9 @@ const AppLayout = ({ children }: { children: React.ReactNode }) => {
14 14
   const skipLayoutPrefixes = [
15 15
     '/user/chat/',
16 16
     '/user/persona/create',
17
-    '/user/knowledge/create'
17
+    '/user/knowledge/create',
18
+    '/user/settings/profile',
19
+    '/user/payment'
18 20
   ];
19 21
 
20 22
   const shouldSkipLayout = skipLayoutPrefixes.some(prefix =>

+ 1
- 1
app/user/page.tsx 查看文件

@@ -13,7 +13,7 @@ const { Title, Text } = Typography;
13 13
 const page = () => {
14 14
     return (
15 15
         <Layout className="!space-y-4 !bg-white">
16
-            <PageTitle title="DASHBOARD" />
16
+            <PageTitle>DASHBOARD</PageTitle>
17 17
 
18 18
             {/* Plan Details */}
19 19
             <Row>

+ 122
- 109
app/user/payment/page.tsx 查看文件

@@ -1,144 +1,157 @@
1 1
 "use client";
2 2
 
3
-import { useState } from 'react'
3
+import { useCallback, useState } from 'react';
4 4
 import PageTitle from '@/components/ui/PageTitle';
5
-import { Typography, Button, Input, Form, Select, Switch } from 'antd'
5
+import { Typography, Button, Input, Form, Select, Switch, Flex } from 'antd';
6 6
 import Link from 'next/link';
7 7
 import { BankFilled, WalletFilled } from '@ant-design/icons';
8 8
 import type { PaymentType } from '@/types/payment';
9 9
 import { useQuery } from '@tanstack/react-query';
10 10
 import { getPaymentType } from '@/app/api/general/paymentService';
11
+import AltLayout from '@/components/layout/AltLayout';
11 12
 
12 13
 const { Text, Title } = Typography;
13 14
 
14
-const iconMapper = {
15
-  "card": <WalletFilled className='!text-white !text-xl' />,
16
-  "bank": <BankFilled className='!text-white !text-xl' />
17
-};
18
-
19 15
 const CreatePersona: React.FC = () => {
20
-  const [selectedPaymentID, setSelectedPaymentID] = useState<number | undefined>()
21
-  const [companyName, setCompanyName] = useState("")
22
-  const [cardNumber, setCardNumber] = useState("")
23
-  const [cvc, setCvc] = useState("")
16
+  // Form states
17
+  const [selectedPaymentID, setSelectedPaymentID] = useState<number | undefined>();
18
+  const [companyName, setCompanyName] = useState('');
19
+  const [cardNumber, setCardNumber] = useState('');
20
+  const [cvc, setCvc] = useState('');
24 21
 
22
+  // Fetch payment types using React Query
25 23
   const { data: paymentType, error, isLoading } = useQuery<PaymentType[] | undefined>({
26
-    queryKey: ["getPaymentType"],
27
-    queryFn: () => getPaymentType()
24
+    queryKey: ['getPaymentType'],
25
+    queryFn: getPaymentType
28 26
   });
29 27
 
30
-  if (isLoading) {
31
-    return <p>Loading...</p>;
32
-  }
28
+  const renderIcon = useCallback((nameId: string) => {
29
+    if (nameId === "card") return <WalletFilled className='!text-white !text-xl' />
30
+    else if (nameId === "bank") return <BankFilled className='!text-white !text-xl' />
31
+    else return <></>
32
+  }, [])
33
+
34
+  if (isLoading) return <p>Loading...</p>;
33 35
 
34 36
   return (
35
-    <div className="flex flex-col bg-white">
36
-      <PageTitle title='PAYMENT' />
37
-      <div className='p-4 px-8 '>
38
-        <div className='flex flex-col gap-5 mb-8'>
39
-          <div className='text-xs'>
40
-            <p className='font-semibold'>Enter your payment details</p>
41
-            <p className='font-semibold italic'>
42
-              By continuing you agree to our <Link href="/">Terms</Link>
37
+    <AltLayout header={<PageTitle backButton={true}>PAYMENT</PageTitle>}>
38
+      <Flex vertical className='!bg-white'>
39
+        <div className='p-4'>
40
+          {/* Section intro */}
41
+          <div className='flex flex-col gap-5 mb-8 text-xs text-gray-400'>
42
+            <p className='font-semibold'>Enter your payment details <br />
43
+              <span className='font-semibold italic'>
44
+                By continuing you agree to our <Link href="/">Terms</Link>
45
+              </span>
43 46
             </p>
44 47
           </div>
45
-        </div>
46 48
 
47
-        <div className='flex flex-row flex-wrap gap-2'>
48
-          {paymentType?.map(({ id, type, description, icon_id }) => (
49
-            <div
50
-              key={id}
51
-              className={`${selectedPaymentID === id ? 'bg-blue-950' : 'bg-gray-200'} hover:bg-blue-950 transition-all ease-in-out rounded-lg p-4 max-w-[160px] cursor-pointer`}
52
-              onClick={() => setSelectedPaymentID(id)}
53
-            >
54
-              {iconMapper[icon_id]}
55
-              <p className='text-white'>{`Transfer via card number`}</p>
56
-            </div>
57
-          ))}
58
-        </div>
49
+          {/* Payment type selection */}
50
+          <div className='flex flex-row flex-wrap gap-2'>
51
+            {paymentType?.map(({ id, type, description, icon_id }) => (
52
+              <div
53
+                key={id}
54
+                className={`
55
+                  ${selectedPaymentID === id ? 'bg-blue-950' : 'bg-gray-400'} 
56
+                  hover:bg-blue-950 transition-all ease-in-out 
57
+                  rounded-lg p-4 max-w-[160px] cursor-pointer
58
+                `}
59
+                onClick={() => setSelectedPaymentID(id)}
60
+              >
61
+                {renderIcon(icon_id)}
62
+                <p className='text-white'>Transfer via card number</p>
63
+              </div>
64
+            ))}
65
+          </div>
59 66
 
60
-        <div className="px-2 mt-4">
61
-          <Form layout="vertical">
62
-            <div className="grid grid-cols-1 sm:grid-cols-2">
63
-              <Form.Item label={<Text className='!italic !text-xs !font-semibold'>Company Name</Text>}>
64
-                <Input
65
-                  placeholder="Company Name"
66
-                  value={companyName}
67
-                  onChange={(e) => setCompanyName(e.target.value)}
68
-                />
69
-              </Form.Item>
70
-
71
-              <Form.Item label={<Text className='!italic !text-xs !font-semibold'>Card Number</Text>}>
72
-                <Input
73
-                  value={cardNumber}
74
-                  onChange={(e) => {
75
-                    const rawValue = e.target.value.replace(/\D/g, '').slice(0, 16);
76
-                    const formattedValue = rawValue.replace(/(.{4})/g, '$1 ').trim();
77
-                    setCardNumber(formattedValue);
78
-                  }}
79
-                />
80
-              </Form.Item>
81
-
82
-              <div className='flex flex-row gap-5'>
83
-                <Form.Item label={<Text className='!italic !text-xs !font-semibold'>Exp Month</Text>} className="w-full">
84
-                  <Select
85
-                    allowClear
86
-                    style={{ width: '100%' }}
87
-                    placeholder="Please select"
88
-                    options={
89
-                      Array.from({ length: 12 }, (_, i) => {
90
-                        const month = String(i + 1).padStart(2, '0');
91
-                        return { label: month, value: month };
92
-                      })
93
-                    }
94
-                  />
95
-                </Form.Item>
67
+          {/* Payment form */}
68
+          <div className="px-2 mt-4">
69
+            <Form layout="vertical">
70
+              <div className="grid grid-cols-1 sm:grid-cols-2">
96 71
 
97
-                <Form.Item label={<Text className='!italic !text-xs !font-semibold'>Exp Year</Text>} className="w-full">
98
-                  <Select
99
-                    allowClear
100
-                    style={{ width: '100%' }}
101
-                    placeholder="Please select"
102
-                    options={
103
-                      Array.from({ length: 10 }, (_, i) => {
104
-                        const year = new Date().getFullYear() + i;
105
-                        return { label: String(year), value: String(year) };
106
-                      })
107
-                    }
72
+                {/* Company Name */}
73
+                <Form.Item label={<Text className='!italic !text-xs !font-semibold'>Company Name</Text>}>
74
+                  <Input
75
+                    placeholder="Company Name"
76
+                    value={companyName}
77
+                    onChange={(e) => setCompanyName(e.target.value)}
108 78
                   />
109 79
                 </Form.Item>
110
-              </div>
111 80
 
112
-              <Form.Item label={<Text className='!italic !text-xs !font-semibold'>CVC</Text>}>
113
-                <div className='flex gap-6 items-center'>
81
+                {/* Card Number with formatting */}
82
+                <Form.Item label={<Text className='!italic !text-xs !font-semibold'>Card Number</Text>}>
114 83
                   <Input
115
-                    placeholder="123"
116
-                    className='!max-w-[50px]'
117
-                    value={cvc}
84
+                    value={cardNumber}
118 85
                     onChange={(e) => {
119
-                      const rawValue = e.target.value.replace(/\D/g, '').slice(0, 4);
120
-                      setCvc(rawValue);
86
+                      const rawValue = e.target.value.replace(/\D/g, '').slice(0, 16);
87
+                      const formattedValue = rawValue.replace(/(.{4})/g, '$1 ').trim();
88
+                      setCardNumber(formattedValue);
121 89
                     }}
122 90
                   />
123
-                  <p className='text-gray-300 max-w-[160px]' style={{ fontSize: 10 }}>
124
-                    3 or 4 digits usually found on the signature strips
125
-                  </p>
126
-                </div>
127
-              </Form.Item>
91
+                </Form.Item>
92
+
93
+                {/* Expiration Month & Year */}
94
+                <div className='flex flex-row gap-5'>
95
+                  <Form.Item label={<Text className='!italic !text-xs !font-semibold'>Exp Month</Text>} className="w-full">
96
+                    <Select
97
+                      allowClear
98
+                      placeholder="Please select"
99
+                      options={Array.from({ length: 12 }, (_, i) => {
100
+                        const month = String(i + 1).padStart(2, '0');
101
+                        return { label: month, value: month };
102
+                      })}
103
+                    />
104
+                  </Form.Item>
128 105
 
129
-              <Form.Item>
130
-                <div className='flex flex-row items-center gap-2'>
131
-                  <Switch checked={true} onChange={() => { }} />
132
-                  <Text className='!text-xs font-semibold'>SET AS DEFAULT</Text>
106
+                  <Form.Item label={<Text className='!italic !text-xs !font-semibold'>Exp Year</Text>} className="w-full">
107
+                    <Select
108
+                      allowClear
109
+                      placeholder="Please select"
110
+                      options={Array.from({ length: 10 }, (_, i) => {
111
+                        const year = new Date().getFullYear() + i;
112
+                        return { label: String(year), value: String(year) };
113
+                      })}
114
+                    />
115
+                  </Form.Item>
133 116
                 </div>
134
-              </Form.Item>
135
-            </div>
136
-            <Button type="primary" className='!w-full !py-3'>CONFIRM</Button>
137
-          </Form>
117
+
118
+                {/* CVC with note */}
119
+                <Form.Item label={<Text className='!italic !text-xs !font-semibold'>CVC</Text>}>
120
+                  <div className='flex gap-6 items-center'>
121
+                    <Input
122
+                      placeholder="123"
123
+                      className='!max-w-[50px]'
124
+                      value={cvc}
125
+                      onChange={(e) => {
126
+                        const rawValue = e.target.value.replace(/\D/g, '').slice(0, 4);
127
+                        setCvc(rawValue);
128
+                      }}
129
+                    />
130
+                    <p className='text-gray-300 max-w-[160px]' style={{ fontSize: 10 }}>
131
+                      3 or 4 digits usually found on the signature strip
132
+                    </p>
133
+                  </div>
134
+                </Form.Item>
135
+
136
+                {/* Default payment switch */}
137
+                <Form.Item>
138
+                  <div className='flex flex-row items-center gap-2'>
139
+                    <Switch checked={true} onChange={() => { }} />
140
+                    <Text className='!text-xs font-semibold'>SET AS DEFAULT</Text>
141
+                  </div>
142
+                </Form.Item>
143
+              </div>
144
+
145
+              {/* Submit Button */}
146
+              <Button type="primary" className='!w-full !py-3'>
147
+                CONFIRM
148
+              </Button>
149
+            </Form>
150
+          </div>
138 151
         </div>
139
-      </div>
140
-    </div>
141
-  )
142
-}
152
+      </Flex>
153
+    </AltLayout>
154
+  );
155
+};
143 156
 
144 157
 export default CreatePersona;

+ 19
- 18
app/user/persona/create/page.tsx 查看文件

@@ -13,6 +13,8 @@ import type { RcFile } from 'antd/es/upload';
13 13
 import PhoneInput from 'react-phone-input-2';
14 14
 import 'react-phone-input-2/lib/style.css';
15 15
 
16
+const { Text, Title } = Typography
17
+
16 18
 const CreatePersona: React.FC = () => {
17 19
 
18 20
     const [name, setName] = useState<string | undefined>("")
@@ -67,7 +69,6 @@ const CreatePersona: React.FC = () => {
67 69
         return false;
68 70
     };
69 71
 
70
-
71 72
     return (
72 73
         <AltLayout header={<PageTitle backButton={true}>Create Persona</PageTitle>}>
73 74
             <Row className='px-4'>
@@ -145,66 +146,66 @@ const CreatePersona: React.FC = () => {
145 146
 
146 147
                         <Form.Item label={<p className='font-bold'>Persona Training Center</p>}>
147 148
                             <Flex vertical gap={10}>
148
-                                <Flex gap={10} className='!items-center'>
149
+                                <Flex gap={10}>
149 150
                                     <Switch
150 151
                                         checked={enabled.isManualKnowledgeEntry}
151 152
                                         onChange={(checked) =>
152 153
                                             setEnabled({ ...enabled, isManualKnowledgeEntry: checked })
153 154
                                         }
154 155
                                     />
155
-                                    <span className='font-bold'>Manual Knowledge Entry</span>
156
+                                    <Text className='font-bold'>Manual Knowledge Entry</Text>
156 157
                                 </Flex>
157
-                                <div className='flex items-center gap-2'>
158
+                                <Flex gap={10}>
158 159
                                     <Switch
159 160
                                         checked={enabled.isUploadTextDocument}
160 161
                                         onChange={(checked) =>
161 162
                                             setEnabled({ ...enabled, isUploadTextDocument: checked })
162 163
                                         }
163 164
                                     />
164
-                                    <span className='font-bold'>Upload Text Document</span>
165
-                                </div>
166
-                                <div className='flex items-center gap-2'>
165
+                                    <Text className='font-bold'>Upload Text Document</Text>
166
+                                </Flex>
167
+                                <Flex gap={10}>
167 168
                                     <Switch
168 169
                                         checked={enabled.isImportWebLink}
169 170
                                         onChange={(checked) =>
170 171
                                             setEnabled({ ...enabled, isImportWebLink: checked })
171 172
                                         }
172 173
                                     />
173
-                                    <span className="font-bold">
174
+                                    <Text className="font-bold">
174 175
                                         Import from Web Link{' '}
175 176
                                         <Tag color="blue" className="font-semibold text-xs px-2 py-[2px] !rounded-full">
176 177
                                             Premium
177 178
                                         </Tag>
178
-                                    </span>
179
-                                </div>
180
-                                <div className='flex items-center gap-2'>
179
+                                    </Text>
180
+                                </Flex>
181
+                                <Flex gap={10}>
181 182
                                     <Switch
182 183
                                         checked={enabled.isDallEImageGen}
183 184
                                         onChange={(checked) =>
184 185
                                             setEnabled({ ...enabled, isDallEImageGen: checked })
185 186
                                         }
186 187
                                     />
187
-                                    <span className="font-bold">
188
+                                    <Text className="font-bold">
188 189
                                         DALL-E Image Generation{' '}
189 190
                                         <Tag color="blue" className="font-semibold text-xs px-2 py-[2px] !rounded-full">
190 191
                                             Premium
191 192
                                         </Tag>
192
-                                    </span>
193
-                                </div>
194
-                                <div className='flex items-center gap-2'>
193
+                                    </Text>
194
+                                </Flex>
195
+                                <Flex gap={10}>
195 196
                                     <Switch
196 197
                                         checked={enabled.isSOPAutoLearn}
197 198
                                         onChange={(checked) =>
198 199
                                             setEnabled({ ...enabled, isSOPAutoLearn: checked })
199 200
                                         }
200 201
                                     />
201
-                                    <span className="font-bold">
202
+                                    <Text className="font-bold">
202 203
                                         Enable SOP Auto-Learning{' '}
203 204
                                         <Tag color="blue" className="font-semibold text-xs px-2 py-[2px] !rounded-full">
204 205
                                             Premium
205 206
                                         </Tag>
206
-                                    </span>
207
-                                </div>
207
+                                    </Text>
208
+                                </Flex>
208 209
                             </Flex>
209 210
                         </Form.Item>
210 211
 

+ 0
- 135
app/user/profile/page.tsx 查看文件

@@ -1,135 +0,0 @@
1
-'use client'
2
-
3
-import {
4
-    UploadOutlined,
5
-    DeleteOutlined
6
-} from '@ant-design/icons'
7
-import { Button, Input, Typography, Upload, Form } from 'antd'
8
-import { useState } from 'react'
9
-
10
-const { Title, Text } = Typography
11
-
12
-const ProfileSettings = () => {
13
-    const [companyName, setCompanyName] = useState('')
14
-    const [role, setRole] = useState('')
15
-    const [profileName, setProfileName] = useState('')
16
-    const [newPassword, setNewPassword] = useState('')
17
-    const [confirmPassword, setConfirmPassword] = useState('')
18
-
19
-    return (
20
-        <Form layout="vertical" className="!flex !flex-col !gap-y-8 !max-w-2xl !mx-auto !p-5">
21
-            {/* 1. Profile Photo */}
22
-            <div>
23
-                <p className="font-bold text-white bg-pink-300 py-1 px-5 w-fit rounded-full">
24
-                    Profile Photo
25
-                </p>
26
-                <div className="flex flex-col items-center gap-4 mt-4">
27
-                    <img
28
-                        src="/default-avatar.png"
29
-                        alt="Profile"
30
-                        className="w-20 h-20 rounded-full object-cover border"
31
-                    />
32
-                    <Upload showUploadList={false}>
33
-                        <Button type='primary'>
34
-                            <span className='font-bold'>Upload Photo</span>
35
-                        </Button>
36
-                    </Upload>
37
-                </div>
38
-            </div>
39
-
40
-            {/* 2. Company Info */}
41
-            <div>
42
-                <p className="font-bold text-white bg-pink-300 py-1 px-5 w-fit rounded-full">
43
-                    Company Info
44
-                </p>
45
-                <div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-4">
46
-                    <Form.Item label={<Title level={5}>Company Name</Title>}>
47
-                        <Input
48
-                            placeholder="Company Name"
49
-                            value={companyName}
50
-                            onChange={(e) => setCompanyName(e.target.value)}
51
-                        />
52
-                    </Form.Item>
53
-                    <Form.Item label={<Title level={5}>My Role</Title>}>
54
-                        <Input
55
-                            placeholder="My Role"
56
-                            value={role}
57
-                            onChange={(e) => setRole(e.target.value)}
58
-                        />
59
-                    </Form.Item>
60
-                </div>
61
-            </div>
62
-
63
-            {/* 3. Profile Name */}
64
-            <div>
65
-                <p className="font-bold text-white bg-pink-300 py-1 px-5 w-fit rounded-full">
66
-                    Profile Name
67
-                </p>
68
-                <div className="mt-4">
69
-                    <Form.Item label={<Title level={5}>Profile Name</Title>}>
70
-                        <Input
71
-                            placeholder="Profile Name"
72
-                            value={profileName}
73
-                            onChange={(e) => setProfileName(e.target.value)}
74
-                        />
75
-                    </Form.Item>
76
-                </div>
77
-            </div>
78
-
79
-            {/* 4. Change Password */}
80
-            <div>
81
-                <p className="font-bold text-white bg-pink-300 py-1 px-5 w-fit rounded-full">
82
-                    Change Password
83
-                </p>
84
-                <div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-4">
85
-                    <Form.Item label={<Title level={5}>New Password</Title>}>
86
-                        <Input.Password
87
-                            placeholder="New Password"
88
-                            value={newPassword}
89
-                            onChange={(e) => setNewPassword(e.target.value)}
90
-                        />
91
-                    </Form.Item>
92
-                    <Form.Item label={<Title level={5}>Confirm Password</Title>}>
93
-                        <Input.Password
94
-                            placeholder="Confirm Password"
95
-                            value={confirmPassword}
96
-                            onChange={(e) => setConfirmPassword(e.target.value)}
97
-                        />
98
-                    </Form.Item>
99
-                </div>
100
-                <Button
101
-                    type="primary"
102
-                    className="mt-4 w-fit mx-auto"
103
-                    onClick={() => console.log('Change password confirmed')}
104
-                >
105
-                    <span className='px-10 font-bold'>Save</span>
106
-                </Button>
107
-            </div>
108
-
109
-            {/* 5. Delete Account */}
110
-            <div>
111
-                <div className="flex items-center gap-2 mb-2">
112
-                    <DeleteOutlined className="text-xl" style={{ color: "red" }} />
113
-                    <p className="font-bold text-red-600 py-1 w-fit">
114
-                        Delete Account
115
-                    </p>
116
-                </div>
117
-                <Text type="danger">
118
-                    Your account and data will be permanently deleted.
119
-                </Text>
120
-                <div className="mt-4 flex flex-col">
121
-                    <Button
122
-                        danger
123
-                        className='w-fit mx-auto'
124
-                        type="primary"
125
-                        onClick={() => console.log('Account deletion confirmed')}
126
-                    >
127
-                        <span className='px-10 font-bold'>Delete</span>
128
-                    </Button>
129
-                </div>
130
-            </div>
131
-        </Form>
132
-    )
133
-}
134
-
135
-export default ProfileSettings

+ 156
- 0
app/user/settings/profile/page.tsx 查看文件

@@ -0,0 +1,156 @@
1
+'use client';
2
+
3
+import { useState } from 'react';
4
+import {
5
+    UploadOutlined,
6
+    DeleteOutlined,
7
+} from '@ant-design/icons';
8
+import {
9
+    Button,
10
+    Input,
11
+    Typography,
12
+    Upload,
13
+    Form,
14
+    Row,
15
+    Col,
16
+    Divider,
17
+    Flex,
18
+} from 'antd';
19
+
20
+import AltLayout from '@/components/layout/AltLayout';
21
+import PageTitle from '@/components/ui/PageTitle';
22
+
23
+const { Title, Text } = Typography;
24
+
25
+const ProfileSettings: React.FC = () => {
26
+    const [companyName, setCompanyName] = useState('');
27
+    const [role, setRole] = useState('');
28
+    const [profileName, setProfileName] = useState('');
29
+    const [newPassword, setNewPassword] = useState('');
30
+    const [confirmPassword, setConfirmPassword] = useState('');
31
+
32
+    return (
33
+        <AltLayout header={<PageTitle backButton={true}>Profile Settings</PageTitle>}>
34
+            <Row justify="center">
35
+                <Col xs={24} sm={20} md={16} lg={12}>
36
+                    <Form layout="vertical" className="px-4 py-6 space-y-10">
37
+
38
+                        <Row>
39
+                            <Col span={24}>
40
+                                <Title level={5} className="!mb-3">Profile Photo</Title>
41
+                                <Flex vertical align="center" gap={16}>
42
+                                    <img
43
+                                        src="/default-avatar.png"
44
+                                        alt="Profile"
45
+                                        className="w-20 h-20 rounded-full object-cover border"
46
+                                    />
47
+                                    <Upload showUploadList={false}>
48
+                                        <Button icon={<UploadOutlined />} type="primary">
49
+                                            Upload Photo
50
+                                        </Button>
51
+                                    </Upload>
52
+                                </Flex>
53
+                            </Col>
54
+                            <Divider />
55
+                            <Col span={24}>
56
+                                <Title level={5} className="!mb-3">Company Info</Title>
57
+                                <Row gutter={16}>
58
+                                    <Col xs={24} sm={12}>
59
+                                        <Form.Item label="Company Name">
60
+                                            <Input
61
+                                                placeholder="Company Name"
62
+                                                value={companyName}
63
+                                                onChange={(e) => setCompanyName(e.target.value)}
64
+                                            />
65
+                                        </Form.Item>
66
+                                    </Col>
67
+                                    <Col xs={24} sm={12}>
68
+                                        <Form.Item label="My Role">
69
+                                            <Input
70
+                                                placeholder="My Role"
71
+                                                value={role}
72
+                                                onChange={(e) => setRole(e.target.value)}
73
+                                            />
74
+                                        </Form.Item>
75
+                                    </Col>
76
+                                </Row>
77
+                            </Col>
78
+                            <Divider />
79
+
80
+                            {/* Profile Name */}
81
+                            <Col span={24}>
82
+                                <Title level={5} className="!mb-3">Profile Name</Title>
83
+                                <Form.Item label="Profile Name">
84
+                                    <Input
85
+                                        placeholder="Profile Name"
86
+                                        value={profileName}
87
+                                        onChange={(e) => setProfileName(e.target.value)}
88
+                                    />
89
+                                </Form.Item>
90
+                            </Col>
91
+
92
+                            <Divider />
93
+
94
+                            {/* Change Password */}
95
+                            <Col span={24}>
96
+                                <Title level={5} className="!mb-3">Change Password</Title>
97
+                                <Row gutter={16}>
98
+                                    <Col xs={24} sm={12}>
99
+                                        <Form.Item label="New Password">
100
+                                            <Input.Password
101
+                                                placeholder="New Password"
102
+                                                value={newPassword}
103
+                                                onChange={(e) => setNewPassword(e.target.value)}
104
+                                            />
105
+                                        </Form.Item>
106
+                                    </Col>
107
+                                    <Col xs={24} sm={12}>
108
+                                        <Form.Item label="Confirm Password">
109
+                                            <Input.Password
110
+                                                placeholder="Confirm Password"
111
+                                                value={confirmPassword}
112
+                                                onChange={(e) => setConfirmPassword(e.target.value)}
113
+                                            />
114
+                                        </Form.Item>
115
+                                    </Col>
116
+                                </Row>
117
+                                <Button
118
+                                    type="primary"
119
+                                    className="mt-2"
120
+                                    onClick={() => console.log('Change password confirmed')}
121
+                                >
122
+                                    Save Password
123
+                                </Button>
124
+                            </Col>
125
+
126
+                            <Divider />
127
+
128
+                            {/* Delete Account */}
129
+                            <Col span={24}>
130
+                                <Flex align="center" gap={8} className="mb-2">
131
+                                    <DeleteOutlined className="text-xl text-red-500" />
132
+                                    <Text strong className="text-red-500">Delete Account</Text>
133
+                                </Flex>
134
+                                <Text type="danger">
135
+                                    Your account and data will be permanently deleted. This action cannot be undone.
136
+                                </Text>
137
+                                <div className="mt-4">
138
+                                    <Button
139
+                                        danger
140
+                                        type="primary"
141
+                                        onClick={() => console.log('Account deletion confirmed')}
142
+                                    >
143
+                                        Delete Account
144
+                                    </Button>
145
+                                </div>
146
+                            </Col>
147
+                        </Row>
148
+
149
+                    </Form>
150
+                </Col>
151
+            </Row>
152
+        </AltLayout>
153
+    );
154
+};
155
+
156
+export default ProfileSettings;

+ 88
- 47
app/user/wallet/page.tsx 查看文件

@@ -1,65 +1,106 @@
1 1
 'use client';
2 2
 
3 3
 import React, { useState } from 'react';
4
-import PageTitle from '@/components/ui/PageTitle';
5
-import { Input, Radio, Typography } from 'antd';
6 4
 import Link from 'next/link';
5
+import { useRouter } from 'next/navigation';
6
+import PageTitle from '@/components/ui/PageTitle';
7
+import {
8
+    Typography,
9
+    Input,
10
+    Button,
11
+    Radio,
12
+    Row,
13
+    Col,
14
+    Card,
15
+    Form,
16
+    Space,
17
+} from 'antd';
7 18
 
8
-const { Text } = Typography;
19
+const { Text, Title } = Typography;
9 20
 
10 21
 const Wallet: React.FC = () => {
11 22
     const [amount, setAmount] = useState('');
12 23
     const [autoRenew, setAutoRenew] = useState(false);
13 24
 
25
+    const router = useRouter();
26
+
14 27
     return (
15
-        <main className="flex flex-col bg-white min-h-screen">
16
-            <PageTitle title="WALLET" />
28
+        <main className="min-h-screen bg-white">
29
+            {/* Page Header */}
30
+            <PageTitle>Wallet</PageTitle>
31
+
32
+            <Row justify="center" className="mt-6 px-4">
33
+                <Col xs={24} sm={20} md={16} lg={12}>
34
+                    <Form layout="vertical" className="space-y-6">
35
+
36
+                        {/* 1. Balance + History Link */}
37
+                        <Form.Item>
38
+                            <Space className="w-full justify-between" align="center">
39
+                                <Text strong>Current Balance</Text>
40
+                                <Link
41
+                                    href="/transaction-history"
42
+                                    className="text-blue-500 underline text-sm"
43
+                                >
44
+                                    Transaction History
45
+                                </Link>
46
+                            </Space>
47
+                        </Form.Item>
17 48
 
18
-            <div className="flex flex-col gap-y-6 mt-6 max-w-md">
19
-                <div className='px-3'>
20
-                    {/* 1. Top Section: Title + History */}
21
-                    <div className="flex justify-between items-center mb-2">
22
-                        <p className="font-bold">Current Balance</p>
23
-                        <Link href="/transaction-history" className="text-blue-500 underline text-sm">
24
-                            Transaction History
25
-                        </Link>
26
-                    </div>
49
+                        {/* 2. Top-Up Section */}
50
+                        <Form.Item label="Top-Up Amount (RM)">
51
+                            <Input
52
+                                placeholder="Enter amount"
53
+                                type="number"
54
+                                value={amount}
55
+                                onChange={(e) => setAmount(e.target.value)}
56
+                                size="large"
57
+                                className="border-blue-500 bg-blue-50"
58
+                            />
59
+                        </Form.Item>
27 60
 
28
-                    {/* 2. RM Input */}
29
-                    <div className='flex flex-col'>
30
-                        <Input
31
-                            className="border border-blue-500 bg-blue-50 mb-3"
32
-                            placeholder="Enter amount in RM"
33
-                            type='number'
34
-                            value={amount}
35
-                            onChange={(e) => setAmount(e.target.value)}
36
-                            prefix="RM"
37
-                            size="large"
38
-                        />
39
-                        <button className='w-fit rounded-lg text-xs px-4 py-2 bg-[#369cc1] hover:bg-[#436d86] text-white shadow border-0 mb-3 ms-auto'>
40
-                            <span className='font-bold'>Top Up Wallet</span>
41
-                        </button>
42
-                    </div>
61
+                        <Form.Item className="!text-right">
62
+                            <Button
63
+                                type="primary"
64
+                                className="!text-xs !font-bold !px-6 !py-2"
65
+                                onClick={() => {
66
+                                    router.push('/user/payment')
67
+                                }}
68
+                            >
69
+                                Top Up Wallet
70
+                            </Button>
71
+                        </Form.Item>
43 72
 
44
-                    <div className="flex items-start gap-3 px-3">
45
-                        <Radio
46
-                            checked={autoRenew}
47
-                            onChange={(e) => setAutoRenew(e.target.checked)}
48
-                        />
49
-                        <div>
50
-                            <Text strong>Auto-Renew Subscription</Text>
51
-                            <p className="text-xs text-gray-500">
52
-                                Enable monthly or yearly auto payment using wallet.
53
-                            </p>
54
-                        </div>
55
-                    </div>
56
-                </div>
73
+                        {/* 3. Auto-Renew */}
74
+                        <Form.Item>
75
+                            <Row align="top" gutter={16}>
76
+                                <Col>
77
+                                    <Radio
78
+                                        checked={autoRenew}
79
+                                        onChange={(e) => setAutoRenew(e.target.checked)}
80
+                                    />
81
+                                </Col>
82
+                                <Col flex="auto">
83
+                                    <Text strong>Auto-Renew Subscription</Text>
84
+                                    <p className="text-xs text-gray-500">
85
+                                        Enable monthly or yearly auto payment using wallet.
86
+                                    </p>
87
+                                </Col>
88
+                            </Row>
89
+                        </Form.Item>
57 90
 
58
-                {/* 4. Current Plan */}
59
-                <div className='border-y-2 p-3 border-blue-700'>
60
-                    <p><span className='font-bold'>Current Plan:</span> <span >Premium (RM25/Month)</span> </p>
61
-                </div>
62
-            </div>
91
+                        {/* 4. Current Plan Display */}
92
+                        <Card
93
+                            bordered
94
+                            className="border-blue-700 border-2"
95
+                            bodyStyle={{ padding: '12px' }}
96
+                        >
97
+                            <Text>
98
+                                <Text strong>Current Plan:</Text> Premium (RM25/Month)
99
+                            </Text>
100
+                        </Card>
101
+                    </Form>
102
+                </Col>
103
+            </Row>
63 104
         </main>
64 105
     );
65 106
 };

+ 31
- 14
components/layout/AltLayout.tsx 查看文件

@@ -1,39 +1,56 @@
1
-import React from 'react'
1
+import React from 'react';
2 2
 import { Flex, Layout, Row, Col } from 'antd';
3
-import Navigation from '@/components/layout/Navigation'
3
+import Navigation from '@/components/layout/Navigation';
4
+
5
+// This layout component is an alternative layout for Next.js routes 
6
+// where the default layout from app/layout.tsx is intentionally skipped.
7
+// It is useful when you define certain paths to avoid the global layout (e.g., login pages, special full-screen pages).
4 8
 
5 9
 type AltLayoutProps = {
6
-    header?: React.ReactNode,
7
-    children?: React.ReactNode,
8
-    footer?: React.ReactNode
9
-}
10
+    header?: React.ReactNode;    // Optional header component
11
+    children?: React.ReactNode;  // Main content of the page
12
+    footer?: React.ReactNode;    // Optional footer component (defaults to <Navigation />)
13
+};
10 14
 
11
-const AltLayout: React.FC<AltLayoutProps> = ({ header = <></>, children = <></>, footer =<Navigation /> }:AltLayoutProps) => {
15
+// Functional component definition with default props set
16
+const AltLayout: React.FC<AltLayoutProps> = ({
17
+    header = <></>,              // Empty fragment by default if no header passed
18
+    children = <></>,            // Empty fragment by default if no children passed
19
+    footer = <Navigation />      // Defaults to Navigation if no footer is passed
20
+}: AltLayoutProps) => {
12 21
     return (
22
+        // Top-level Layout from Ant Design
13 23
         <Layout className="!w-full !max-w-[430px] !mx-auto !relative !bg-white">
14
-            <Flex vertical className='!h-screen'>
24
+            {/* Full vertical height flex container */}
25
+            <Flex vertical className="!h-screen">
26
+
27
+                {/* Header Row (if provided) */}
15 28
                 <Row>
16 29
                     <Col span={24}>
17 30
                         {header}
18 31
                     </Col>
19 32
                 </Row>
20
-                <Row className='flex-1 overflow-y-scroll overflow-x-hidden'>
33
+
34
+                {/* Content Row: grows to take available space, scrollable vertically only */}
35
+                <Row className="flex-1 overflow-y-scroll overflow-x-hidden">
21 36
                     <Col span={24}>
22 37
                         <Flex vertical className="!bg-white">
23
-                            {/* Chat messages */}
38
+                            {/* Content wrapper - handles chat body or main content scroll */}
24 39
                             <div className="flex-1 overflow-y-auto px-4 py-6 space-y-4">
25 40
                                 {children}
26 41
                             </div>
27
-
28 42
                         </Flex>
29 43
                     </Col>
30 44
                 </Row>
45
+
46
+                {/* Footer section - typically bottom navigation */}
31 47
                 <div>
32 48
                     {footer}
33 49
                 </div>
50
+
34 51
             </Flex>
35 52
         </Layout>
36
-    )
37
-}
53
+    );
54
+};
38 55
 
39
-export default AltLayout
56
+export default AltLayout;

+ 1
- 1
components/layout/Navigation.tsx 查看文件

@@ -19,7 +19,7 @@ const navItems = [
19 19
         label: 'Chat',
20 20
     },
21 21
     {
22
-        key: '/user/profile',
22
+        key: '/user/settings/profile',
23 23
         icon: <UserOutlined />,
24 24
         label: 'Profile',
25 25
     },

Loading…
取消
儲存