checkout.component.html (8894B)
1 <form [formGroup]="checkoutForm" (ngSubmit)="onSubmit()"> 2 <section class="card mb-3 col"> 3 <div class="card-body row g-3"> 4 <h5 class="fs-6">Billing Information</h5> 5 <div class="mb-3 col-6"> 6 <label class="form-label"> 7 First Name 8 <span class="text-danger">*</span> 9 <input 10 type="text" 11 class="form-control" 12 [class.is-invalid]="isFieldInvalid('firstName')" 13 placeholder="John" 14 formControlName="firstName" /> 15 @if (isFieldInvalid('firstName')) { 16 <div class="invalid-feedback d-block"> 17 <i class="bi bi-exclamation-circle me-1"></i> 18 {{ getFieldError('firstName') }} 19 </div> 20 } 21 </label> 22 </div> 23 24 <!-- Last Name --> 25 <div class="mb-3 col-6"> 26 <label class="form-label"> 27 Last Name 28 <span class="text-danger">*</span> 29 <input 30 type="text" 31 class="form-control" 32 [class.is-invalid]="isFieldInvalid('lastName')" 33 placeholder="Doe" 34 formControlName="lastName" /> 35 @if (isFieldInvalid('lastName')) { 36 <div class="invalid-feedback d-block"> 37 <i class="bi bi-exclamation-circle me-1"></i> 38 {{ getFieldError('lastName') }} 39 </div> 40 } 41 </label> 42 </div> 43 44 <!-- Email --> 45 <div class="mb-3 col-6"> 46 <label class="form-label"> 47 Email 48 <span class="text-danger">*</span> 49 <input 50 type="email" 51 class="form-control" 52 [class.is-invalid]="isFieldInvalid('email')" 53 placeholder="name@example.com" 54 formControlName="email" /> 55 @if (isFieldInvalid('email')) { 56 <div class="invalid-feedback d-block"> 57 <i class="bi bi-exclamation-circle me-1"></i> 58 {{ getFieldError('email') }} 59 </div> 60 } 61 </label> 62 </div> 63 64 <!-- Phone Number --> 65 <div class="mb-3 col-6"> 66 <label class="form-label"> 67 Phone Number 68 <span class="text-danger">*</span> 69 <input 70 type="tel" 71 class="form-control" 72 [class.is-invalid]="isFieldInvalid('phoneNumber')" 73 placeholder="+1 (555) 123-4567" 74 formControlName="phoneNumber" /> 75 @if (isFieldInvalid('phoneNumber')) { 76 <div class="invalid-feedback d-block"> 77 <i class="bi bi-exclamation-circle me-1"></i> 78 {{ getFieldError('phoneNumber') }} 79 </div> 80 } 81 </label> 82 </div> 83 84 <!-- Card Input --> 85 <div class="mb-3 col-6"> 86 <label class="form-label"> 87 Card Number 88 <span class="text-danger">*</span> 89 </label> 90 <div class="card-input"></div> 91 @if (submitted() && cardInputComponent && !cardInputComponent.isValidCard()) { 92 <div class="invalid-feedback d-block"> 93 <i class="bi bi-exclamation-circle me-1"></i> 94 Please enter a valid 16-digit card number 95 </div> 96 } 97 </div> 98 </div> 99 </section> 100 101 <!-- Address Section --> 102 <section class="card mb-3 col"> 103 <div class="card-body row g-3"> 104 <h5 class="fs-6">Shipping Address</h5> 105 <!-- Address Line 1 --> 106 <div class="mb-3 col-12"> 107 <label class="form-label"> 108 Address Line 1 109 <span class="text-danger">*</span> 110 <input 111 type="text" 112 class="form-control" 113 [class.is-invalid]="isFieldInvalid('addressLine1')" 114 placeholder="123 Main St" 115 formControlName="addressLine1" /> 116 @if (isFieldInvalid('addressLine1')) { 117 <div class="invalid-feedback d-block"> 118 <i class="bi bi-exclamation-circle me-1"></i> 119 {{ getFieldError('addressLine1') }} 120 </div> 121 } 122 </label> 123 </div> 124 125 <!-- Address Line 2 --> 126 <div class="mb-3 col-12"> 127 <label class="form-label"> 128 Address Line 2 (Optional) 129 <input 130 type="text" 131 class="form-control" 132 placeholder="Apt, Suite, Unit, etc." 133 formControlName="addressLine2" /> 134 </label> 135 </div> 136 137 <!-- City --> 138 <div class="mb-3 col-6"> 139 <label class="form-label"> 140 City 141 <span class="text-danger">*</span> 142 <input 143 type="text" 144 class="form-control" 145 [class.is-invalid]="isFieldInvalid('city')" 146 placeholder="City" 147 formControlName="city" /> 148 @if (isFieldInvalid('city')) { 149 <div class="invalid-feedback d-block"> 150 <i class="bi bi-exclamation-circle me-1"></i> 151 {{ getFieldError('city') }} 152 </div> 153 } 154 </label> 155 </div> 156 157 <!-- State / Province --> 158 <div class="mb-3 col-6"> 159 <label class="form-label"> 160 State / Province 161 <span class="text-danger">*</span> 162 <input 163 type="text" 164 class="form-control" 165 [class.is-invalid]="isFieldInvalid('state')" 166 placeholder="State / Province" 167 formControlName="state" /> 168 @if (isFieldInvalid('state')) { 169 <div class="invalid-feedback d-block"> 170 <i class="bi bi-exclamation-circle me-1"></i> 171 {{ getFieldError('state') }} 172 </div> 173 } 174 </label> 175 </div> 176 177 <!-- ZIP / Postal Code --> 178 <div class="mb-3 col-6"> 179 <label class="form-label"> 180 ZIP / Postal Code 181 <span class="text-danger">*</span> 182 <input 183 type="text" 184 class="form-control" 185 [class.is-invalid]="isFieldInvalid('zipCode')" 186 placeholder="12345" 187 formControlName="zipCode" /> 188 @if (isFieldInvalid('zipCode')) { 189 <div class="invalid-feedback d-block"> 190 <i class="bi bi-exclamation-circle me-1"></i> 191 {{ getFieldError('zipCode') }} 192 </div> 193 } 194 </label> 195 </div> 196 197 <!-- Country --> 198 <div class="mb-3 col-6"> 199 <label class="form-label"> 200 Country 201 <span class="text-danger">*</span> 202 <input 203 type="text" 204 class="form-control" 205 [class.is-invalid]="isFieldInvalid('country')" 206 placeholder="US" 207 formControlName="country" /> 208 @if (isFieldInvalid('country')) { 209 <div class="invalid-feedback d-block"> 210 <i class="bi bi-exclamation-circle me-1"></i> 211 {{ getFieldError('country') }} 212 </div> 213 } 214 </label> 215 </div> 216 </div> 217 </section> 218 219 <!-- Shipping Options Section --> 220 <section class="card mb-3"> 221 <div class="card-body"> 222 <h5 class="fs-6">Shipping Options <span class="text-danger">*</span></h5> 223 <div class="list-group"> 224 @for (option of shippingOptions; track option.value) { 225 <label class="list-group-item"> 226 <input class="form-check-input me-2" type="radio" [value]="option.value" formControlName="shippingOption" /> 227 <i class="bi {{ option.icon }} me-2"></i> 228 {{ option.label }} 229 </label> 230 } 231 </div> 232 @if (isFieldInvalid('shippingOption')) { 233 <div class="invalid-feedback d-block mt-2"> 234 <i class="bi bi-exclamation-circle me-1"></i> 235 {{ getFieldError('shippingOption') }} 236 </div> 237 } 238 </div> 239 </section> 240 241 <!-- Terms & Conditions Section --> 242 <section class="card mb-3"> 243 <div class="card-body"> 244 <div class="form-check"> 245 <input 246 class="form-check-input" 247 type="checkbox" 248 id="agreeToTerms" 249 formControlName="agreeToTerms" 250 [class.is-invalid]="isFieldInvalid('agreeToTerms')" /> 251 <label class="form-check-label" for="agreeToTerms"> 252 I agree to the payment terms and confirm the order 253 <span class="text-danger">*</span> 254 </label> 255 @if (isFieldInvalid('agreeToTerms')) { 256 <div class="invalid-feedback d-block"> 257 <i class="bi bi-exclamation-circle me-1"></i> 258 You must agree to the terms before proceeding 259 </div> 260 } 261 </div> 262 </div> 263 </section> 264 265 <!-- Submit Button --> 266 <div class="d-grid"> 267 <button type="submit" class="btn btn-primary btn-sm btn-lg" [disabled]="isSubmitting()"> 268 @if (isSubmitting()) { 269 <span class="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span> 270 Processing... 271 } @else { 272 <i class="bi bi-credit-card me-2"></i> 273 Place Order 274 } 275 </button> 276 </div> 277 </form>