juice-shop
254 строки · 9.9 Кб
1/*
2* Copyright (c) 2014-2024 Bjoern Kimminich & the OWASP Juice Shop contributors.
3* SPDX-License-Identifier: MIT
4*/
5
6import { UntypedFormControl, Validators } from '@angular/forms'
7import { Component, NgZone, type OnInit } from '@angular/core'
8import { ConfigurationService } from '../Services/configuration.service'
9import { BasketService } from '../Services/basket.service'
10import { TranslateService } from '@ngx-translate/core'
11import { library } from '@fortawesome/fontawesome-svg-core'
12import {
13faCartArrowDown,
14faCoffee,
15faGift,
16faHandHoldingUsd,
17faHeart,
18faStickyNote,
19faThumbsUp,
20faTimes,
21faTshirt,
22faPalette
23} from '@fortawesome/free-solid-svg-icons'
24import { faLeanpub, faStripe } from '@fortawesome/free-brands-svg-icons'
25import { QrCodeComponent } from '../qr-code/qr-code.component'
26import { MatDialog } from '@angular/material/dialog'
27import { ActivatedRoute, type ParamMap, Router } from '@angular/router'
28import { WalletService } from '../Services/wallet.service'
29import { DeliveryService } from '../Services/delivery.service'
30import { UserService } from '../Services/user.service'
31import { CookieService } from 'ngx-cookie'
32import { Location } from '@angular/common'
33import { SnackBarHelperService } from '../Services/snack-bar-helper.service'
34
35library.add(faCartArrowDown, faGift, faHeart, faLeanpub, faThumbsUp, faTshirt, faStickyNote, faHandHoldingUsd, faCoffee, faTimes, faStripe, faPalette)
36
37@Component({
38selector: 'app-payment',
39templateUrl: './payment.component.html',
40styleUrls: ['./payment.component.scss']
41})
42export class PaymentComponent implements OnInit {
43public couponConfirmation: any
44public couponError: any
45public card: any = {}
46public twitterUrl = null
47public facebookUrl = null
48public applicationName = 'OWASP Juice Shop'
49private campaignCoupon: string
50public couponControl: UntypedFormControl = new UntypedFormControl('', [Validators.required, Validators.minLength(10), Validators.maxLength(10)])
51public clientDate: any
52public paymentId: any = undefined
53public couponPanelExpanded: boolean = false
54public paymentPanelExpanded: boolean = false
55public mode: any
56public walletBalance: number = 0
57public walletBalanceStr: string
58public totalPrice: any = 0
59public paymentMode: string = 'card'
60private readonly campaigns = {
61WMNSDY2019: { validOn: 1551999600000, discount: 75 },
62WMNSDY2020: { validOn: 1583622000000, discount: 60 },
63WMNSDY2021: { validOn: 1615158000000, discount: 60 },
64WMNSDY2022: { validOn: 1646694000000, discount: 60 },
65WMNSDY2023: { validOn: 1678230000000, discount: 60 },
66ORANGE2020: { validOn: 1588546800000, discount: 50 },
67ORANGE2021: { validOn: 1620082800000, discount: 40 },
68ORANGE2022: { validOn: 1651618800000, discount: 40 },
69ORANGE2023: { validOn: 1683154800000, discount: 40 }
70}
71
72constructor (private readonly location: Location, private readonly cookieService: CookieService,
73private readonly userService: UserService, private readonly deliveryService: DeliveryService, private readonly walletService: WalletService,
74private readonly router: Router, private readonly dialog: MatDialog, private readonly configurationService: ConfigurationService,
75private readonly basketService: BasketService, private readonly translate: TranslateService,
76private readonly activatedRoute: ActivatedRoute, private readonly ngZone: NgZone,
77private readonly snackBarHelperService: SnackBarHelperService) { }
78
79ngOnInit () {
80this.initTotal()
81this.walletService.get().subscribe((balance) => {
82this.walletBalance = balance
83this.walletBalanceStr = parseFloat(balance).toFixed(2)
84}, (err) => { console.log(err) })
85this.couponPanelExpanded = localStorage.getItem('couponPanelExpanded') ? JSON.parse(localStorage.getItem('couponPanelExpanded')) : false
86this.paymentPanelExpanded = localStorage.getItem('paymentPanelExpanded') ? JSON.parse(localStorage.getItem('paymentPanelExpanded')) : false
87
88this.configurationService.getApplicationConfiguration().subscribe((config) => {
89if (config?.application?.social) {
90if (config.application.social.twitterUrl) {
91this.twitterUrl = config.application.social.twitterUrl
92}
93if (config.application.social.facebookUrl) {
94this.facebookUrl = config.application.social.facebookUrl
95}
96if (config.application.name) {
97this.applicationName = config.application.name
98}
99}
100}, (err) => { console.log(err) })
101}
102
103initTotal () {
104this.activatedRoute.paramMap.subscribe((paramMap: ParamMap) => {
105this.mode = paramMap.get('entity')
106if (this.mode === 'wallet') {
107this.totalPrice = parseFloat(sessionStorage.getItem('walletTotal'))
108} else if (this.mode === 'deluxe') {
109this.userService.deluxeStatus().subscribe((res) => {
110this.totalPrice = res.membershipCost
111}, (err) => { console.log(err) })
112} else {
113const itemTotal = parseFloat(sessionStorage.getItem('itemTotal'))
114const promotionalDiscount = sessionStorage.getItem('couponDiscount') ? (parseFloat(sessionStorage.getItem('couponDiscount')) / 100) * itemTotal : 0
115this.deliveryService.getById(sessionStorage.getItem('deliveryMethodId')).subscribe((method) => {
116const deliveryPrice = method.price
117this.totalPrice = itemTotal + deliveryPrice - promotionalDiscount
118})
119}
120}, (err) => { console.log(err) })
121}
122
123applyCoupon () {
124this.campaignCoupon = this.couponControl.value
125this.clientDate = new Date()
126// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
127const offsetTimeZone = (this.clientDate.getTimezoneOffset() + 60) * 60 * 1000
128this.clientDate.setHours(0, 0, 0, 0)
129this.clientDate = this.clientDate.getTime() - offsetTimeZone
130// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
131sessionStorage.setItem('couponDetails', `${this.campaignCoupon}-${this.clientDate}`)
132const campaign = this.campaigns[this.couponControl.value]
133if (campaign) {
134if (this.clientDate === campaign.validOn) {
135this.showConfirmation(campaign.discount)
136} else {
137this.couponConfirmation = undefined
138this.translate.get('INVALID_COUPON').subscribe((invalidCoupon) => {
139this.couponError = { error: invalidCoupon }
140}, (translationId) => {
141this.couponError = { error: translationId }
142})
143this.resetCouponForm()
144}
145} else {
146this.basketService.applyCoupon(Number(sessionStorage.getItem('bid')), encodeURIComponent(this.couponControl.value)).subscribe((discount: any) => {
147this.showConfirmation(discount)
148}, (err) => {
149this.couponConfirmation = undefined
150this.couponError = err
151this.resetCouponForm()
152})
153}
154}
155
156showConfirmation (discount) {
157this.resetCouponForm()
158this.couponError = undefined
159sessionStorage.setItem('couponDiscount', discount)
160this.translate.get('DISCOUNT_APPLIED', { discount }).subscribe((discountApplied) => {
161this.couponConfirmation = discountApplied
162}, (translationId) => {
163this.couponConfirmation = translationId
164})
165this.initTotal()
166}
167
168getMessage (id) {
169this.paymentId = id
170this.paymentMode = 'card'
171}
172
173routeToPreviousUrl () {
174this.location.back()
175}
176
177choosePayment () {
178sessionStorage.removeItem('itemTotal')
179if (this.mode === 'wallet') {
180this.walletService.put({ balance: this.totalPrice, paymentId: this.paymentId }).subscribe(() => {
181sessionStorage.removeItem('walletTotal')
182this.ngZone.run(async () => await this.router.navigate(['/wallet']))
183this.snackBarHelperService.open('CHARGED_WALLET', 'confirmBar')
184}, (err) => {
185console.log(err)
186this.snackBarHelperService.open(err.error?.message, 'errorBar')
187})
188} else if (this.mode === 'deluxe') {
189this.userService.upgradeToDeluxe(this.paymentMode, this.paymentId).subscribe((data) => {
190localStorage.setItem('token', data.token)
191this.cookieService.put('token', data.token)
192this.ngZone.run(async () => await this.router.navigate(['/deluxe-membership']))
193}, (err) => { console.log(err) })
194} else {
195if (this.paymentMode === 'wallet') {
196if (this.walletBalance < this.totalPrice) {
197this.snackBarHelperService.open('INSUFFICIENT_WALLET_BALANCE', 'errorBar')
198return
199}
200sessionStorage.setItem('paymentId', 'wallet')
201} else {
202sessionStorage.setItem('paymentId', this.paymentId)
203}
204this.ngZone.run(async () => await this.router.navigate(['/order-summary']))
205}
206}
207
208// eslint-disable-next-line no-empty,@typescript-eslint/no-empty-function
209noop () { }
210
211showBitcoinQrCode () {
212this.dialog.open(QrCodeComponent, {
213data: {
214data: 'bitcoin:1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm',
215url: './redirect?to=https://blockchain.info/address/1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm',
216address: '1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm',
217title: 'TITLE_BITCOIN_ADDRESS'
218}
219})
220}
221
222showDashQrCode () {
223this.dialog.open(QrCodeComponent, {
224data: {
225data: 'dash:Xr556RzuwX6hg5EGpkybbv5RanJoZN17kW',
226url: './redirect?to=https://explorer.dash.org/address/Xr556RzuwX6hg5EGpkybbv5RanJoZN17kW',
227address: 'Xr556RzuwX6hg5EGpkybbv5RanJoZN17kW',
228title: 'TITLE_DASH_ADDRESS'
229}
230})
231}
232
233showEtherQrCode () {
234this.dialog.open(QrCodeComponent, {
235data: {
236data: '0x0f933ab9fCAAA782D0279C300D73750e1311EAE6',
237url: './redirect?to=https://etherscan.io/address/0x0f933ab9fcaaa782d0279c300d73750e1311eae6',
238address: '0x0f933ab9fCAAA782D0279C300D73750e1311EAE6',
239title: 'TITLE_ETHER_ADDRESS'
240}
241})
242}
243
244useWallet () {
245this.paymentMode = 'wallet'
246this.choosePayment()
247}
248
249resetCouponForm () {
250this.couponControl.setValue('')
251this.couponControl.markAsPristine()
252this.couponControl.markAsUntouched()
253}
254}
255