git.iko.soy/dashared/hookah-tau
on develop help sign in
Merge pull request #25 from dashared/admin/build-4

Admin/build 4 - новые фичи админа

commit82894e962955bb608cb8fa7917e37265f1bf7f5a authorDarya Rednikina <31587869+dashared@users.noreply.github.com> dateThu 9 Jan 2020, 19:24 (7 years ago) parentc896aefad92d08
18 files changed+461−114
Hookah Tau.xcodeproj/project.pbxproj+6−2 Hookah Tau/API/ClientsService/ClientsService.swift+17 Hookah Tau/API/ClientsService/Resolvers/BlocklistPutResolver.swift+33 Hookah Tau/Controllers/Admin/Clients/Cells/ClientTableViewCell.swift+8−2 Hookah Tau/Controllers/Admin/Clients/ClientList.storyboard+111−63 Hookah Tau/Controllers/Admin/Clients/ClientsViewController.swift+128−6 Hookah Tau/Controllers/Admin/Clients/Profile/ProfileTableViewController.swift+86−18 Hookah Tau/Controllers/Admin/Reservations/Views/No reserv/AdminNoReservationsView.swift+5 Hookah Tau/Controllers/Admin/Reservations/Views/No reserv/AdminNoReservationsView.xib+1 Hookah Tau/Controllers/Client/Reservations/Steps/1/FirstStepView.xib+18−18 Hookah Tau/Controllers/Client/Reservations/Steps/2/SecondStepView.xib+2−2 Hookah Tau/Controllers/Client/Reservations/Steps/3/ThirdStepView.xib+3−3 Hookah Tau/HFunc.swift+7 Hookah Tau/Models/User.swift+9 Hookah Tau/Supporting Files/Assets.xcassets/admin.imageset/Contents.json+12 Hookah Tau/Supporting Files/Assets.xcassets/admin.imageset/admin.pdf Hookah Tau/Supporting Files/Assets.xcassets/blacklist.imageset/Contents.json+15 Hookah Tau/Supporting Files/Assets.xcassets/blacklist.imageset/blacklist.pdf
Hookah Tau.xcodeproj/project.pbxproj+6−2
@@ -97,6 +97,7 @@
9797 12D8FA31237F08C700305F57 /* AllReservations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D8FA30237F08C700305F57 /* AllReservations.swift */; };
9898 12D928AF23C47DCF0051724D /* ADeleteReservationResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D928AE23C47DCF0051724D /* ADeleteReservationResolver.swift */; };
9999 12D928B123C486380051724D /* BaseTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D928B023C486380051724D /* BaseTableViewController.swift */; };
100+ 12D928B323C7464B0051724D /* BlocklistPutResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D928B223C7464B0051724D /* BlocklistPutResolver.swift */; };
100101 12DBEEB223539F2100AF1BB6 /* Client.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 12DBEEB123539F2100AF1BB6 /* Client.storyboard */; };
101102 12E35071239FA8CA004BB188 /* Extensions+String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E35070239FA8CA004BB188 /* Extensions+String.swift */; };
102103 12E35074239FAF52004BB188 /* ClientsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E35073239FAF52004BB188 /* ClientsService.swift */; };
@@ -253,6 +254,7 @@
253254 12D8FA30237F08C700305F57 /* AllReservations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllReservations.swift; sourceTree = "<group>"; };
254255 12D928AE23C47DCF0051724D /* ADeleteReservationResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ADeleteReservationResolver.swift; sourceTree = "<group>"; };
255256 12D928B023C486380051724D /* BaseTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTableViewController.swift; sourceTree = "<group>"; };
257+ 12D928B223C7464B0051724D /* BlocklistPutResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlocklistPutResolver.swift; sourceTree = "<group>"; };
256258 12DBEEB123539F2100AF1BB6 /* Client.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Client.storyboard; sourceTree = "<group>"; };
257259 12E35070239FA8CA004BB188 /* Extensions+String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Extensions+String.swift"; sourceTree = "<group>"; };
258260 12E35073239FAF52004BB188 /* ClientsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientsService.swift; sourceTree = "<group>"; };
@@ -711,6 +713,7 @@
711713 children = (
712714 12E35077239FAFA4004BB188 /* ClientsListResolver.swift */,
713715 12E3507C239FD1F3004BB188 /* ClientReservationsResolver.swift */,
716+ 12D928B223C7464B0051724D /* BlocklistPutResolver.swift */,
714717 );
715718 path = Resolvers;
716719 sourceTree = "<group>";
@@ -1154,6 +1157,7 @@
11541157 F3895F4A233D323700FA6A37 /* CodeCoordinator.swift in Sources */,
11551158 12B3A7B923ACCD83009E2FA6 /* AddOtherAdminResolver.swift in Sources */,
11561159 12E3507F239FDFC2004BB188 /* ClientProfileCoordinator.swift in Sources */,
1160+ 12D928B323C7464B0051724D /* BlocklistPutResolver.swift in Sources */,
11571161 12838EB4236779C700CEF108 /* ApiResolver.swift in Sources */,
11581162 12838EA9236764A600CEF108 /* APIClient.swift in Sources */,
11591163 123615D12355141600D1122A /* ProfileView.swift in Sources */,
@@ -1410,7 +1414,7 @@
14101414 buildSettings = {
14111415 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
14121416 CODE_SIGN_STYLE = Automatic;
1413− CURRENT_PROJECT_VERSION = 3;
1417+ CURRENT_PROJECT_VERSION = 4;
14141418 DEVELOPMENT_TEAM = 23S94LRHD8;
14151419 INFOPLIST_FILE = "Hookah Tau/Info.plist";
14161420 IPHONEOS_DEPLOYMENT_TARGET = 11.0;
@@ -1430,7 +1434,7 @@
14301434 buildSettings = {
14311435 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
14321436 CODE_SIGN_STYLE = Automatic;
1433− CURRENT_PROJECT_VERSION = 3;
1437+ CURRENT_PROJECT_VERSION = 4;
14341438 DEVELOPMENT_TEAM = 23S94LRHD8;
14351439 INFOPLIST_FILE = "Hookah Tau/Info.plist";
14361440 IPHONEOS_DEPLOYMENT_TARGET = 11.0;
Hookah Tau/API/ClientsService/ClientsService.swift+17
@@ -63,4 +63,21 @@ class ClientsService {
6363 }
6464
6565 }
66+
67+ /// Метод для удаления или добавления пользователя в чс
68+ func changeBlockList(whatToDo: CrudMethod, phone: String, completion: @escaping ((Bool) -> Void)) {
69+ let resolver = BlocklistPutResolver(blockList: [phone])
70+ let request = ApiRequest(resolver: resolver, httpMethod: whatToDo)
71+
72+ apiClient.load(request: request.request) { (res) in
73+ switch res {
74+ case .failure:
75+ completion(false)
76+ return
77+ case .success:
78+ completion(true)
79+ return
80+ }
81+ }
82+ }
6683}
Hookah Tau/API/ClientsService/Resolvers/BlocklistPutResolver.swiftnew file+33
@@ -0,0 +1,33 @@
1+//
2+// BlocklistPutResolver.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 09/01/2020.
6+// Copyright © 2020 Daria Rednikina. All rights reserved.
7+//
8+
9+import Foundation
10+
11+struct RequestBlocklist: MyCodable {
12+ var blockList: [String]
13+}
14+
15+class BlocklistPutResolver: ApiResolver {
16+ var name: String {
17+ return "/blocklist"
18+ }
19+
20+ var groupName: String? {
21+ return "/admin"
22+ }
23+
24+ var blockList: [String]
25+
26+ init(blockList: [String]) {
27+ self.blockList = blockList
28+ }
29+
30+ func parameters() -> MyCodable? {
31+ return RequestBlocklist(blockList: blockList)
32+ }
33+}
Hookah Tau/Controllers/Admin/Clients/Cells/ClientTableViewCell.swift+8−2
@@ -20,6 +20,11 @@ class ClientTableViewCell: UITableViewCell {
2020
2121 @IBOutlet weak var numberOfReservationsLabel: UILabel!
2222
23+ @IBOutlet weak var blockListImage: UIImageView!
24+
25+ @IBOutlet weak var isAdminImage: UIImageView!
26+
27+
2328 // MARK: - Lifecycle
2429
2530 override func awakeFromNib() {
@@ -36,8 +41,9 @@ class ClientTableViewCell: UITableViewCell {
3641 // MARK: - Bind
3742
3843 func bind(withModel model: Client) {
39− let name = model.name ?? "❔"
40− nameLabel.text = model.isAdmin ? "👑 " + name : name
44+ blockListImage.isHidden = !model.isBlocked
45+ isAdminImage.isHidden = !model.isAdmin
46+ nameLabel.text = model.name ?? "❔"
4147 phoneNumberLabel.text = model.phoneNumber.formattedNumber()
4248 numberOfReservationsLabel.text = "\(model.reservationCount)"
4349 }
Hookah Tau/Controllers/Admin/Clients/ClientList.storyboard+111−63
@@ -1,9 +1,10 @@
11<?xml version="1.0" encoding="UTF-8"?>
2−<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
2+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
33 <device id="retina4_7" orientation="portrait" appearance="light"/>
44 <dependencies>
55 <deployment identifier="iOS"/>
6− <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
6+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
7+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
78 <capability name="Stack View standard spacing" minToolsVersion="9.0"/>
89 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
910 </dependencies>
@@ -30,12 +31,17 @@
3031 <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="top" translatesAutoresizingMaskIntoConstraints="NO" id="vNV-bN-3No">
3132 <rect key="frame" x="0.0" y="0.0" width="179" height="53"/>
3233 <subviews>
33− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Стасик" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4Cp-jh-0Gq">
34+ <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" alignment="center" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="uoO-w2-5yG">
3435 <rect key="frame" x="0.0" y="0.0" width="78.5" height="26.5"/>
35− <fontDescription key="fontDescription" type="boldSystem" pointSize="22"/>
36− <color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
37− <nil key="highlightedColor"/>
38− </label>
36+ <subviews>
37+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Стасик" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4Cp-jh-0Gq">
38+ <rect key="frame" x="0.0" y="0.0" width="78.5" height="26.5"/>
39+ <fontDescription key="fontDescription" type="boldSystem" pointSize="22"/>
40+ <color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
41+ <nil key="highlightedColor"/>
42+ </label>
43+ </subviews>
44+ </stackView>
3945 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="+7 (901) 733-01-79" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0gY-h5-AV2">
4046 <rect key="frame" x="0.0" y="29" width="179" height="24"/>
4147 <fontDescription key="fontDescription" type="system" pointSize="20"/>
@@ -45,16 +51,40 @@
4551 </subviews>
4652 </stackView>
4753 <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="tJg-ju-bFY">
48− <rect key="frame" x="310.5" y="0.0" width="32.5" height="53"/>
54+ <rect key="frame" x="215.5" y="0.0" width="127.5" height="53"/>
4955 <subviews>
50− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="3" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Gzo-kW-60Z">
51− <rect key="frame" x="0.0" y="14.5" width="12.5" height="24"/>
52− <fontDescription key="fontDescription" type="system" pointSize="20"/>
53− <nil key="textColor"/>
54− <nil key="highlightedColor"/>
55− </label>
56+ <stackView opaque="NO" contentMode="scaleToFill" spacing="40" translatesAutoresizingMaskIntoConstraints="NO" id="4et-BC-7iY">
57+ <rect key="frame" x="0.0" y="14" width="107.5" height="25"/>
58+ <subviews>
59+ <stackView opaque="NO" contentMode="scaleToFill" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="BHD-cD-L1c">
60+ <rect key="frame" x="0.0" y="0.0" width="55" height="25"/>
61+ <subviews>
62+ <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="blacklist" translatesAutoresizingMaskIntoConstraints="NO" id="yw1-jl-Iil">
63+ <rect key="frame" x="0.0" y="0.0" width="25" height="25"/>
64+ <constraints>
65+ <constraint firstAttribute="width" constant="25" id="k7r-sC-Yro"/>
66+ <constraint firstAttribute="height" constant="25" id="kjF-aV-kTo"/>
67+ </constraints>
68+ </imageView>
69+ <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="admin" translatesAutoresizingMaskIntoConstraints="NO" id="Tlq-hK-YHS">
70+ <rect key="frame" x="30" y="0.0" width="25" height="25"/>
71+ <constraints>
72+ <constraint firstAttribute="width" constant="25" id="NSy-Ih-fCV"/>
73+ <constraint firstAttribute="height" constant="25" id="nOu-SF-8Yd"/>
74+ </constraints>
75+ </imageView>
76+ </subviews>
77+ </stackView>
78+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="3" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Gzo-kW-60Z">
79+ <rect key="frame" x="95" y="0.0" width="12.5" height="25"/>
80+ <fontDescription key="fontDescription" type="system" pointSize="20"/>
81+ <nil key="textColor"/>
82+ <nil key="highlightedColor"/>
83+ </label>
84+ </subviews>
85+ </stackView>
5686 <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="arrow" translatesAutoresizingMaskIntoConstraints="NO" id="DrQ-Ss-gIT">
57− <rect key="frame" x="20.5" y="16.5" width="12" height="20"/>
87+ <rect key="frame" x="115.5" y="16.5" width="12" height="20"/>
5888 </imageView>
5989 </subviews>
6090 </stackView>
@@ -69,6 +99,8 @@
6999 </constraints>
70100 </tableViewCellContentView>
71101 <connections>
102+ <outlet property="blockListImage" destination="yw1-jl-Iil" id="p09-KQ-ayQ"/>
103+ <outlet property="isAdminImage" destination="Tlq-hK-YHS" id="KZP-yS-8YQ"/>
72104 <outlet property="nameLabel" destination="4Cp-jh-0Gq" id="g6e-c0-x0u"/>
73105 <outlet property="numberOfReservationsLabel" destination="Gzo-kW-60Z" id="9J2-S4-fKq"/>
74106 <outlet property="phoneNumberLabel" destination="0gY-h5-AV2" id="rdb-GS-ceF"/>
@@ -86,64 +118,80 @@
86118 <point key="canvasLocation" x="0.80000000000000004" y="-112.89355322338831"/>
87119 </scene>
88120 <!--Profile Table View Controller-->
89− <scene sceneID="8Qr-sA-YQr">
121+ <scene sceneID="APa-VZ-6hd">
90122 <objects>
91− <tableViewController storyboardIdentifier="ProfileTableViewController" id="mqB-EY-UGh" customClass="ProfileTableViewController" customModule="Hookah_Tau" customModuleProvider="target" sceneMemberID="viewController">
92− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="N1B-QX-4Kn">
123+ <viewController storyboardIdentifier="ProfileTableViewController" id="ZVH-jf-rtc" customClass="ProfileTableViewController" customModule="Hookah_Tau" customModuleProvider="target" sceneMemberID="viewController">
124+ <view key="view" contentMode="scaleToFill" id="rcq-M9-CvR">
93125 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
94126 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
127+ <subviews>
128+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ciO-ia-Oob">
129+ <rect key="frame" x="0.0" y="0.0" width="375" height="65"/>
130+ <subviews>
131+ <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" alignment="center" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="IBA-bj-CWK">
132+ <rect key="frame" x="8" y="16" width="359" height="37"/>
133+ <subviews>
134+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4WC-gi-jbD" customClass="Button" customModule="Hookah_Tau" customModuleProvider="target">
135+ <rect key="frame" x="0.0" y="0.0" width="180" height="37"/>
136+ <color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
137+ <constraints>
138+ <constraint firstAttribute="width" constant="180" id="bJA-V9-gw9"/>
139+ <constraint firstAttribute="height" constant="37" id="pdo-AO-o8a"/>
140+ </constraints>
141+ <state key="normal" title="Button"/>
142+ </button>
143+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="gfq-ql-lka" customClass="Button" customModule="Hookah_Tau" customModuleProvider="target">
144+ <rect key="frame" x="224" y="0.0" width="135" height="37"/>
145+ <color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
146+ <constraints>
147+ <constraint firstAttribute="width" constant="135" id="Xn3-v6-SLp"/>
148+ <constraint firstAttribute="height" constant="37" id="z68-vW-NjK"/>
149+ </constraints>
150+ <state key="normal" title="Button"/>
151+ </button>
152+ </subviews>
153+ </stackView>
154+ </subviews>
155+ <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
156+ <constraints>
157+ <constraint firstItem="IBA-bj-CWK" firstAttribute="leading" secondItem="ciO-ia-Oob" secondAttribute="leading" constant="8" id="WZS-Vq-tuP"/>
158+ <constraint firstAttribute="trailing" secondItem="IBA-bj-CWK" secondAttribute="trailing" constant="8" id="Yk3-D1-1kg"/>
159+ <constraint firstItem="IBA-bj-CWK" firstAttribute="top" secondItem="ciO-ia-Oob" secondAttribute="top" constant="16" id="fWO-oj-NuN"/>
160+ <constraint firstItem="IBA-bj-CWK" firstAttribute="leading" secondItem="ciO-ia-Oob" secondAttribute="leading" constant="8" id="gP2-jh-5El"/>
161+ <constraint firstAttribute="height" constant="65" id="pzZ-zw-kbc"/>
162+ </constraints>
163+ </view>
164+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="T0s-lX-Z5m">
165+ <rect key="frame" x="0.0" y="65" width="375" height="602"/>
166+ <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
167+ </view>
168+ </subviews>
95169 <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
96− <view key="tableHeaderView" contentMode="scaleToFill" id="oN2-r5-lTy">
97− <rect key="frame" x="0.0" y="0.0" width="375" height="65"/>
98− <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
99− <subviews>
100− <stackView opaque="NO" contentMode="scaleToFill" spacing="47" translatesAutoresizingMaskIntoConstraints="NO" id="UpQ-Uf-0Kc">
101− <rect key="frame" x="8" y="16" width="359" height="37"/>
102− <subviews>
103− <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="nFA-T3-Dxe" customClass="Button" customModule="Hookah_Tau" customModuleProvider="target">
104− <rect key="frame" x="0.0" y="0.0" width="177" height="37"/>
105− <color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
106− <constraints>
107− <constraint firstAttribute="height" constant="37" id="41i-38-mHD"/>
108− <constraint firstAttribute="width" constant="174" id="po9-OR-zq1"/>
109− </constraints>
110− <state key="normal" title="Button"/>
111− </button>
112− <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="HkY-u9-thv" customClass="Button" customModule="Hookah_Tau" customModuleProvider="target">
113− <rect key="frame" x="224" y="0.0" width="135" height="37"/>
114− <color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
115− <constraints>
116− <constraint firstAttribute="height" constant="37" id="LDw-fn-Xem"/>
117− <constraint firstAttribute="width" constant="135" id="swI-oV-Khe"/>
118− </constraints>
119− <state key="normal" title="Button"/>
120− </button>
121− </subviews>
122− </stackView>
123− </subviews>
124− <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
125− <constraints>
126− <constraint firstItem="UpQ-Uf-0Kc" firstAttribute="top" secondItem="oN2-r5-lTy" secondAttribute="top" constant="16" id="58o-fg-n3i"/>
127− <constraint firstItem="UpQ-Uf-0Kc" firstAttribute="leading" secondItem="oN2-r5-lTy" secondAttribute="leading" constant="8" id="5ik-TQ-N4U"/>
128− <constraint firstAttribute="trailing" secondItem="UpQ-Uf-0Kc" secondAttribute="trailing" constant="8" id="8Ca-3C-Xld"/>
129− </constraints>
130− </view>
131− <connections>
132− <outlet property="dataSource" destination="mqB-EY-UGh" id="YZe-zB-7f3"/>
133− <outlet property="delegate" destination="mqB-EY-UGh" id="JPi-98-LhH"/>
134− </connections>
135− </tableView>
170+ <constraints>
171+ <constraint firstItem="ciO-ia-Oob" firstAttribute="trailing" secondItem="tIS-3m-xwG" secondAttribute="trailing" id="3An-sM-OCN"/>
172+ <constraint firstItem="ciO-ia-Oob" firstAttribute="top" secondItem="tIS-3m-xwG" secondAttribute="top" id="5zl-uZ-sTi"/>
173+ <constraint firstItem="T0s-lX-Z5m" firstAttribute="leading" secondItem="tIS-3m-xwG" secondAttribute="leading" id="7qA-Hh-3Us"/>
174+ <constraint firstItem="T0s-lX-Z5m" firstAttribute="trailing" secondItem="tIS-3m-xwG" secondAttribute="trailing" id="9VD-9Q-wGX"/>
175+ <constraint firstItem="T0s-lX-Z5m" firstAttribute="top" secondItem="ciO-ia-Oob" secondAttribute="bottom" id="RSL-fo-wIb"/>
176+ <constraint firstItem="ciO-ia-Oob" firstAttribute="leading" secondItem="tIS-3m-xwG" secondAttribute="leading" id="Tuq-su-gbn"/>
177+ <constraint firstItem="T0s-lX-Z5m" firstAttribute="bottom" secondItem="tIS-3m-xwG" secondAttribute="bottom" id="iQj-LM-Im9"/>
178+ </constraints>
179+ <viewLayoutGuide key="safeArea" id="tIS-3m-xwG"/>
180+ </view>
136181 <connections>
137− <outlet property="copyButton" destination="HkY-u9-thv" id="RLs-cg-y3g"/>
138− <outlet property="phoneButton" destination="nFA-T3-Dxe" id="d7H-jf-NB5"/>
182+ <outlet property="contentView" destination="T0s-lX-Z5m" id="9Z0-5T-f7Z"/>
183+ <outlet property="copyButton" destination="gfq-ql-lka" id="BNi-Ip-AyF"/>
184+ <outlet property="phoneButton" destination="4WC-gi-jbD" id="xlf-g7-CzU"/>
139185 </connections>
140− </tableViewController>
141− <placeholder placeholderIdentifier="IBFirstResponder" id="1YW-I1-Y6m" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
186+ </viewController>
187+ <placeholder placeholderIdentifier="IBFirstResponder" id="g4Y-1k-Lxr" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
142188 </objects>
143− <point key="canvasLocation" x="880.79999999999995" y="-111.0944527736132"/>
189+ <point key="canvasLocation" x="1188" y="-113"/>
144190 </scene>
145191 </scenes>
146192 <resources>
193+ <image name="admin" width="26" height="25"/>
147194 <image name="arrow" width="12" height="20"/>
195+ <image name="blacklist" width="25" height="25"/>
148196 </resources>
149197</document>
Hookah Tau/Controllers/Admin/Clients/ClientsViewController.swift+128−6
@@ -8,7 +8,7 @@
88
99import UIKit
1010
11−class ClientsViewController: UITableViewController {
11+class ClientsViewController: BaseTableViewController {
1212
1313 // MARK: - Properties
1414
@@ -18,16 +18,29 @@ class ClientsViewController: UITableViewController {
1818 }
1919 }
2020
21+ var filteredDataSource: [Client] = []
22+
2123 var clientsService: ClientsService?
2224
2325 weak var coordinator: ClientsCoordinator?
2426
27+ var searchControl: UISearchController?
28+
29+ var isFiltering: Bool {
30+ return searchControl?.isActive ?? false && !searchBarIsEmpty()
31+ }
32+
33+ func searchBarIsEmpty() -> Bool {
34+ return searchControl?.searchBar.text?.isEmpty ?? true
35+ }
36+
2537 // MARK: - Lifecycle
2638
2739 override func viewDidLoad() {
2840 super.viewDidLoad()
2941
30− navigationItem.title = "Клиенты"
42+ setupNavigationBar()
43+ setupSearchController()
3144 clientsService = ClientsService(apiClient: APIClient.shared)
3245 }
3346
@@ -40,6 +53,25 @@ class ClientsViewController: UITableViewController {
4053 super.viewDidAppear(animated)
4154 loadClients()
4255 }
56+
57+ // MARK: - Setup
58+
59+ func setupNavigationBar() {
60+
61+ navigationItem.title = "Клиенты"
62+ navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(shareCSVFile))
63+ }
64+
65+ func setupSearchController() {
66+ searchControl = UISearchController(searchResultsController: nil)
67+ navigationItem.searchController = searchControl
68+ navigationItem.hidesSearchBarWhenScrolling = false
69+ searchControl?.obscuresBackgroundDuringPresentation = false
70+ definesPresentationContext = true
71+ searchControl?.searchResultsUpdater = self
72+ }
73+
74+ // MARK: - Api calls
4375
4476 /// Загружаем клиентов кальянки
4577 func loadClients() {
@@ -53,24 +85,114 @@ class ClientsViewController: UITableViewController {
5385 })
5486 }
5587
88+ // MARK: - Button handlers
89+
90+ /// https://developer.apple.com/design/human-interface-guidelines/ios/views/activity-views/
91+ @objc func shareCSVFile() {
92+ //Your CSV text
93+ let str = HFunc.main.exportClientsToCSV(dataSource)
94+ let filename = getDocumentsDirectory().appendingPathComponent("clients.csv")
95+
96+ do {
97+ try str.write(toFile: filename, atomically: true, encoding: String.Encoding.utf8)
98+
99+ let fileData = NSURL(fileURLWithPath: filename)
100+
101+ let objectsToShare = [fileData]
102+ let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
103+
104+ self.present(activityVC, animated: true, completion: nil)
105+
106+ } catch {
107+ self.displayAlert(with: "По какой-то причине не могу сохранить файл!")
108+ }
109+ }
110+
111+ func getDocumentsDirectory() -> NSString {
112+ let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
113+ let documentsDirectory = paths[0]
114+ return documentsDirectory as NSString
115+ }
116+
117+ // MARK: - Change blocklist status
56118
57− // MARK: - Tableview
119+ func updateUserBlockStatus(wasBlocked: Bool, phone: String, indexPath: IndexPath) {
120+ let crudMethod = wasBlocked ? CrudMethod.delete : CrudMethod.put
121+ clientsService?.changeBlockList(whatToDo: crudMethod, phone: phone, completion: { (res) in
122+ if res {
123+ self.tableView?.beginUpdates()
124+ self.tableView?.reloadRows(at: [indexPath], with: .automatic)
125+ if self.isFiltering {
126+ self.filteredDataSource[indexPath.row].isBlocked = !wasBlocked
127+ let changed = self.filteredDataSource[indexPath.row]
128+ let filtered = self.dataSource.map { (one: Client) -> Client in
129+ if one.uuid == changed.uuid {
130+ return changed
131+ } else { return one } }
132+ self.dataSource = filtered
133+ } else {
134+ self.dataSource[indexPath.row].isBlocked = !wasBlocked
135+ }
136+ self.tableView?.endUpdates()
137+ } else {
138+ self.displayAlert(with: "Не удалось \(wasBlocked ? "удалить" : "добавить") пользователя \(wasBlocked ? "из" : "в") чс! Попробуйте еще раз!")
139+ return
140+ }
141+ })
142+ }
143+}
144+
145+// MARK: - Tableview
146+
147+extension ClientsViewController {
58148
59149 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
60150 let cell = tableView.dequeueReusableCell(withIdentifier: clientTableViewCellId, for: indexPath) as! ClientTableViewCell
61151
62− let userModel = dataSource[indexPath.row]
152+ let userModel = isFiltering ? filteredDataSource[indexPath.row] : dataSource[indexPath.row]
63153 cell.bind(withModel: userModel)
64154
65155 return cell
66156 }
67157
68158 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
69− return dataSource.count
159+ return isFiltering ? filteredDataSource.count : dataSource.count
70160 }
71161
72162 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
73− let user = dataSource[indexPath.row]
163+ let user = isFiltering ? filteredDataSource[indexPath.row] : dataSource[indexPath.row]
74164 coordinator?.openUserProfile(user)
165+ searchControl?.dismiss(animated: true, completion: nil)
166+ }
167+
168+ // Update
169+
170+ override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
171+ return true
172+ }
173+
174+ override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
175+
176+ let user = isFiltering ? filteredDataSource[indexPath.row] : dataSource[indexPath.row]
177+ let blockButton = UITableViewRowAction(style: .normal, title: "\(!user.isBlocked ? "🙅🏻‍♀️" : "👍🏻")") { _,_ in
178+
179+ self.updateUserBlockStatus(wasBlocked: user.isBlocked, phone: user.phoneNumber, indexPath: indexPath)
180+ }
181+
182+ blockButton.backgroundColor = .black
183+
184+ return [blockButton]
185+ }
186+}
187+
188+extension ClientsViewController: UISearchResultsUpdating {
189+ func filterContentForSearchText(_ searchText: String, scope: String = "All")
190+ {
191+ filteredDataSource = dataSource.filter { ($0.name?.lowercased().contains(searchText.lowercased()) ?? false) || ($0.phoneNumber.lowercased().contains(searchText.lowercased())) }
192+ tableView.reloadData()
193+ }
194+
195+ func updateSearchResults(for searchController: UISearchController) {
196+ filterContentForSearchText(searchController.searchBar.text ?? "")
75197 }
76198}
Hookah Tau/Controllers/Admin/Clients/Profile/ProfileTableViewController.swift+86−18
@@ -8,7 +8,7 @@
88
99import UIKit
1010
11−class ProfileTableViewController: BaseTableViewController {
11+class ProfileTableViewController: BaseViewController {
1212
1313 // MARK: - IBAOutlets
1414
@@ -30,24 +30,41 @@ class ProfileTableViewController: BaseTableViewController {
3030 }
3131 }
3232
33+
34+ @IBOutlet weak var contentView: UIView!
35+
3336 // MARK: - properties
3437
38+ var tableView: UITableView?
39+
3540 var clientsService: ClientsService?
3641
3742 var reservationsService: ReservationsService?
3843
39− var user: FullUser? {
40− didSet {
41− guard let u = user else { return }
42− navigationItem.title = u.name
43− }
44− }
44+ var user: FullUser?
4545
4646 weak var coodinator: ClientProfileCoordinator?
4747
48+ var noReserationsYetView: AdminNoReservationsView?
49+
50+ var activityIndicator: UIActivityIndicatorView?
51+
52+ var refreshControl: UIRefreshControl?
53+
4854 var dataSource: [Reservation] = [] {
4955 didSet {
50− tableView.reloadData()
56+ guard let empty = noReserationsYetView else { return }
57+ if dataSource.isEmpty {
58+ empty.alpha = 1
59+ tableView?.alpha = 0
60+ } else {
61+ empty.alpha = 0
62+ tableView?.alpha = 1
63+ }
64+
65+ refreshControl?.endRefreshing()
66+ activityIndicator?.stopAnimating()
67+ tableView?.reloadData()
5168 }
5269 }
5370
@@ -56,10 +73,12 @@ class ProfileTableViewController: BaseTableViewController {
5673 override func viewDidLoad() {
5774 super.viewDidLoad()
5875
59− tableView?.register(ReservationCell.self, forCellReuseIdentifier: reservationCell)
60−
6176 clientsService = ClientsService(apiClient: APIClient.shared)
6277 reservationsService = ReservationsService(apiClient: APIClient.shared)
78+
79+ setupNavBar()
80+ setupTable()
81+ setupActivityIndicator()
6382 loadReservations()
6483 }
6584
@@ -68,13 +87,55 @@ class ProfileTableViewController: BaseTableViewController {
6887 tabBarController?.tabBar.isHidden = true
6988 }
7089
90+ // MARK: - Setup
91+
92+ func setupNavBar() {
93+ guard let u = user else { return }
94+ navigationItem.title = u.name
95+ navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(book))
96+ }
97+
98+ func setupTable() {
99+ tableView = UITableView()
100+
101+ // refresh control
102+ refreshControl = UIRefreshControl()
103+ refreshControl?.addTarget(self, action: #selector(refresh), for: .valueChanged)
104+ tableView?.refreshControl = refreshControl
105+
106+ tableView?.dataSource = self
107+ tableView?.delegate = self
108+
109+ noReserationsYetView = AdminNoReservationsView.loadFromNib()
110+ noReserationsYetView?.setup(withTitle: "У этого пользователя пока нет ни одной брони :(")
111+ noReserationsYetView?.bookButton?.addTarget(self, action: #selector(book), for: .touchUpInside)
112+ contentView.addSubviewThatFills(noReserationsYetView)
113+ noReserationsYetView?.alpha = 0
114+
115+ tableView?.register(ReservationCell.self, forCellReuseIdentifier: reservationCell)
116+
117+ contentView.addSubviewThatFills(tableView)
118+
119+ tableView?.alpha = 0
120+ }
121+
122+ func setupActivityIndicator() {
123+
124+ activityIndicator = UIActivityIndicatorView()
125+ view.addSubviewThatFills(activityIndicator)
126+ activityIndicator?.startAnimating()
127+
128+ }
129+
130+ // MARK: - Api calls
131+
71132 func loadReservations() {
72133 guard let uuid = user?.uuid else { return }
73134 clientsService?.loadReservationsForUser(withUUID: uuid,
74135 completion: { [weak self] (res) in
75136 switch res {
76137 case .failure(let err):
77− print(err)
138+ self?.displayAlert(forError: err)
78139 case .success(let data):
79140 self?.dataSource = data
80141 }
@@ -115,18 +176,25 @@ class ProfileTableViewController: BaseTableViewController {
115176 //Alert
116177 self.displayAlert(with: "Номер скопирован!")
117178 }
118−
179+
180+ @objc func refresh() {
181+ loadReservations()
182+ }
183+
184+ @objc func book() {
185+
186+ }
119187}
120188
121189// MARK: - Table view data source
122190
123−extension ProfileTableViewController {
191+extension ProfileTableViewController: UITableViewDelegate, UITableViewDataSource {
124192
125− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
193+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
126194 return dataSource.count
127195 }
128196
129− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
197+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
130198 let cell = tableView.dequeueReusableCell(withIdentifier: reservationCell, for: indexPath) as! ReservationCell
131199
132200 cell.bind(withModel: dataSource[indexPath.row])
@@ -136,7 +204,7 @@ extension ProfileTableViewController {
136204
137205 // tap
138206
139− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
207+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
140208 guard let u = user else { return }
141209 let r = dataSource[indexPath.row]
142210 let reservation = ReservationWithUser(reservation: r, user: u)
@@ -145,11 +213,11 @@ extension ProfileTableViewController {
145213
146214 // Update
147215
148− override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
216+ func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
149217 return true
150218 }
151219
152− override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
220+ func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
153221
154222 let uuid = dataSource[indexPath.row].uuid
155223 let cancelButton = UITableViewRowAction(style: .normal, title: "❌") { _,_ in
Hookah Tau/Controllers/Admin/Reservations/Views/No reserv/AdminNoReservationsView.swift+5
@@ -12,6 +12,8 @@ class AdminNoReservationsView: UIView {
1212
1313 // MARK: - IBAOutlets
1414
15+ @IBOutlet weak var titleLabel: UILabel?
16+
1517 @IBOutlet weak var bookButton: Button? {
1618 didSet {
1719 let style = BlackButtonStyle()
@@ -19,4 +21,7 @@ class AdminNoReservationsView: UIView {
1921 }
2022 }
2123
24+ func setup(withTitle title: String) {
25+ titleLabel?.text = title
26+ }
2227}
Hookah Tau/Controllers/Admin/Reservations/Views/No reserv/AdminNoReservationsView.xib+1
@@ -46,6 +46,7 @@
4646 <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
4747 <connections>
4848 <outlet property="bookButton" destination="y3F-ua-mLb" id="aC4-gz-Gqd"/>
49+ <outlet property="titleLabel" destination="Svd-DB-3Zu" id="n8Z-Wq-vzC"/>
4950 </connections>
5051 <point key="canvasLocation" x="137.68115942028987" y="91.741071428571431"/>
5152 </view>
Hookah Tau/Controllers/Client/Reservations/Steps/1/FirstStepView.xib+18−18
@@ -1,9 +1,9 @@
11<?xml version="1.0" encoding="UTF-8"?>
2−<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3− <device id="retina4_7" orientation="portrait" appearance="light"/>
2+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3+ <device id="retina5_5" orientation="portrait" appearance="light"/>
44 <dependencies>
55 <deployment identifier="iOS"/>
6− <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
6+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
77 <capability name="Safe area layout guides" minToolsVersion="9.0"/>
88 <capability name="Stack View standard spacing" minToolsVersion="9.0"/>
99 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -106,14 +106,14 @@
106106 </constraints>
107107 </view>
108108 <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="TriangleDown" translatesAutoresizingMaskIntoConstraints="NO" id="5dC-Lq-opV">
109− <rect key="frame" x="184.5" y="0.0" width="45" height="29"/>
109+ <rect key="frame" x="184.66666666666666" y="0.0" width="45" height="29"/>
110110 <constraints>
111111 <constraint firstAttribute="width" constant="45" id="Tsw-fS-8qs"/>
112112 <constraint firstAttribute="height" constant="29" id="YWD-ja-gD5"/>
113113 </constraints>
114114 </imageView>
115115 <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="TriangleUp" translatesAutoresizingMaskIntoConstraints="NO" id="Igw-O9-W92">
116− <rect key="frame" x="184.5" y="196" width="45" height="29"/>
116+ <rect key="frame" x="184.66666666666666" y="196" width="45" height="29"/>
117117 <constraints>
118118 <constraint firstAttribute="height" constant="29" id="AdE-yJ-WLL"/>
119119 <constraint firstAttribute="width" constant="45" id="Eaa-P8-3mv"/>
@@ -159,16 +159,16 @@
159159 <rect key="frame" x="0.0" y="29" width="414" height="59"/>
160160 <subviews>
161161 <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="OEF-Kc-d38">
162− <rect key="frame" x="8" y="5" width="398" height="14.5"/>
162+ <rect key="frame" x="8" y="5.0000000000000009" width="398" height="14.333333333333336"/>
163163 <subviews>
164164 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="November" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5Mn-Mn-qaI">
165− <rect key="frame" x="0.0" y="0.0" width="58.5" height="14.5"/>
165+ <rect key="frame" x="0.0" y="0.0" width="58.333333333333336" height="14.333333333333334"/>
166166 <fontDescription key="fontDescription" type="system" pointSize="12"/>
167167 <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
168168 <nil key="highlightedColor"/>
169169 </label>
170170 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="January" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Rfg-Ts-DX0">
171− <rect key="frame" x="353" y="0.0" width="45" height="14.5"/>
171+ <rect key="frame" x="353" y="0.0" width="45" height="14.333333333333334"/>
172172 <fontDescription key="fontDescription" type="system" pointSize="12"/>
173173 <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
174174 <nil key="highlightedColor"/>
@@ -176,7 +176,7 @@
176176 </subviews>
177177 </stackView>
178178 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="December" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fbc-VX-43f">
179− <rect key="frame" x="176.5" y="5" width="61" height="14.5"/>
179+ <rect key="frame" x="176.66666666666666" y="5.0000000000000009" width="60.666666666666657" height="14.333333333333336"/>
180180 <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="12"/>
181181 <color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
182182 <nil key="highlightedColor"/>
@@ -204,28 +204,28 @@
204204 <constraints>
205205 <constraint firstItem="Y9G-UI-WV7" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="22z-Ck-vsZ"/>
206206 <constraint firstItem="a6N-9A-8y5" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="5c8-YB-dSB"/>
207− <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="954-g3-FZD" secondAttribute="bottom" constant="37" id="C3k-Mb-wT4"/>
207+ <constraint firstAttribute="bottom" secondItem="954-g3-FZD" secondAttribute="bottom" constant="37" id="C3k-Mb-wT4"/>
208208 <constraint firstItem="Y9G-UI-WV7" firstAttribute="top" secondItem="5dC-Lq-opV" secondAttribute="bottom" id="E97-Lg-K2s"/>
209209 <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="fvt-zf-8tU" secondAttribute="trailing" id="Eeh-zB-KWe"/>
210210 <constraint firstItem="a6N-9A-8y5" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="F03-yv-41V"/>
211211 <constraint firstItem="pgz-8G-Kx4" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="G0y-2f-SkS"/>
212212 <constraint firstItem="5dC-Lq-opV" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="If5-v7-UAj"/>
213− <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="pgz-8G-Kx4" secondAttribute="bottom" constant="137" id="Lgn-Nv-wjD"/>
213+ <constraint firstAttribute="bottom" secondItem="pgz-8G-Kx4" secondAttribute="bottom" constant="137" id="Lgn-Nv-wjD"/>
214214 <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="954-g3-FZD" secondAttribute="trailing" id="MGt-d4-Win"/>
215215 <constraint firstItem="fvt-zf-8tU" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="SaI-rP-2em"/>
216216 <constraint firstItem="Igw-O9-W92" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="TtM-Bc-V1U"/>
217− <constraint firstItem="Igw-O9-W92" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="V9u-Eu-VME"/>
217+ <constraint firstItem="Igw-O9-W92" firstAttribute="bottom" secondItem="iN0-l3-epB" secondAttribute="bottom" id="V9u-Eu-VME"/>
218218 <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="pgz-8G-Kx4" secondAttribute="trailing" id="Z6D-PY-Jrh"/>
219219 <constraint firstItem="Igw-O9-W92" firstAttribute="top" secondItem="a6N-9A-8y5" secondAttribute="bottom" constant="8" id="f4D-nq-HMa"/>
220220 <constraint firstItem="Y9G-UI-WV7" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="gZw-8a-dTG"/>
221221 <constraint firstItem="954-g3-FZD" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="itw-0z-3i7"/>
222− <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="fvt-zf-8tU" secondAttribute="bottom" constant="137" id="lOx-ke-O6a"/>
222+ <constraint firstAttribute="bottom" secondItem="fvt-zf-8tU" secondAttribute="bottom" constant="137" id="lOx-ke-O6a"/>
223223 <constraint firstItem="z9p-OK-tL7" firstAttribute="top" secondItem="52e-LM-cF6" secondAttribute="bottom" constant="9" id="ldj-Qh-p0k"/>
224− <constraint firstItem="fvt-zf-8tU" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="29" id="pSg-dd-INI"/>
225− <constraint firstItem="pgz-8G-Kx4" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="29" id="vfO-LG-tqR"/>
226− <constraint firstItem="954-g3-FZD" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="97" id="vhK-2E-j3k"/>
227− <constraint firstItem="5dC-Lq-opV" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" id="xOt-l0-Vzy"/>
228− <constraint firstItem="a6N-9A-8y5" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="97" id="yyf-QB-vfF"/>
224+ <constraint firstItem="fvt-zf-8tU" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="29" id="pSg-dd-INI"/>
225+ <constraint firstItem="pgz-8G-Kx4" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="29" id="vfO-LG-tqR"/>
226+ <constraint firstItem="954-g3-FZD" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="97" id="vhK-2E-j3k"/>
227+ <constraint firstItem="5dC-Lq-opV" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="xOt-l0-Vzy"/>
228+ <constraint firstItem="a6N-9A-8y5" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="97" id="yyf-QB-vfF"/>
229229 </constraints>
230230 <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
231231 <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
Hookah Tau/Controllers/Client/Reservations/Steps/2/SecondStepView.xib+2−2
@@ -123,7 +123,7 @@
123123 </subviews>
124124 <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
125125 <constraints>
126− <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="RJE-Hk-KNh" secondAttribute="bottom" constant="36" id="0W3-e2-hCU"/>
126+ <constraint firstAttribute="bottom" secondItem="RJE-Hk-KNh" secondAttribute="bottom" constant="36" id="0W3-e2-hCU"/>
127127 <constraint firstItem="9c7-IZ-n2p" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="20" id="94y-7J-ksb"/>
128128 <constraint firstItem="9c7-IZ-n2p" firstAttribute="top" secondItem="bJ1-1q-VXq" secondAttribute="bottom" constant="20" id="9TT-vO-7PZ"/>
129129 <constraint firstItem="RJE-Hk-KNh" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="AgS-kP-UNE"/>
@@ -131,7 +131,7 @@
131131 <constraint firstAttribute="trailing" secondItem="bJ1-1q-VXq" secondAttribute="trailing" constant="20" id="OCH-eC-kP5"/>
132132 <constraint firstItem="bJ1-1q-VXq" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="20" id="PCm-nY-M6p"/>
133133 <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="9c7-IZ-n2p" secondAttribute="trailing" constant="20.5" id="Rh7-V2-v2u"/>
134− <constraint firstItem="bJ1-1q-VXq" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="20" id="SnG-Cy-hHq"/>
134+ <constraint firstItem="bJ1-1q-VXq" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="20" id="SnG-Cy-hHq"/>
135135 <constraint firstItem="RJE-Hk-KNh" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="fW0-Tt-MpN"/>
136136 </constraints>
137137 <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
Hookah Tau/Controllers/Client/Reservations/Steps/3/ThirdStepView.xib+3−3
@@ -1,9 +1,9 @@
11<?xml version="1.0" encoding="UTF-8"?>
2−<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
2+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
33 <device id="retina4_7" orientation="portrait" appearance="light"/>
44 <dependencies>
55 <deployment identifier="iOS"/>
6− <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
6+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
77 <capability name="Safe area layout guides" minToolsVersion="9.0"/>
88 <capability name="Stack View standard spacing" minToolsVersion="9.0"/>
99 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -120,7 +120,7 @@
120120 <constraint firstItem="0H2-jJ-gOj" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="20" id="GR6-gI-ecm"/>
121121 <constraint firstItem="ByV-f1-mVO" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="KKj-7n-eQf"/>
122122 <constraint firstItem="0H2-jJ-gOj" firstAttribute="top" secondItem="DL4-0a-WxC" secondAttribute="bottom" constant="30" id="VbN-sb-Pko"/>
123− <constraint firstItem="DL4-0a-WxC" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="20" id="cm0-tz-ta4"/>
123+ <constraint firstItem="DL4-0a-WxC" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="20" id="cm0-tz-ta4"/>
124124 <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="0H2-jJ-gOj" secondAttribute="trailing" constant="20" id="i3D-sP-KlI"/>
125125 <constraint firstAttribute="trailing" secondItem="DL4-0a-WxC" secondAttribute="trailing" constant="20" id="kHp-8n-OTp"/>
126126 <constraint firstItem="DL4-0a-WxC" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="20" id="vOg-X1-y93"/>
Hookah Tau/HFunc.swift+7
@@ -15,6 +15,9 @@ class HFunc {
1515
1616 static let main = HFunc()
1717
18+ func exportClientsToCSV(_ arr: [Client]) -> String {
19+ return arr.reduce(Client.csvHeading) { return funcToMapClientsIntoString($0, $1) }
20+ }
1821
1922 /// Filtering function to get every periods which intersects with given date
2023 /// - Parameter periods: all periods of bookings (for a particular table)
@@ -58,4 +61,8 @@ class HFunc {
5861
5962 return { (period: ReservationPeriod) in intervalChecking(period.startTime, period.endTime) }
6063 }
64+
65+ private func funcToMapClientsIntoString(_ acc: String, _ el: Client) -> String {
66+ return acc + el.toString + "\n"
67+ }
6168}
Hookah Tau/Models/User.swift+9
@@ -30,4 +30,13 @@ struct Client: MyCodable {
3030 var phoneNumber: String
3131 var isAdmin: Bool
3232 var reservationCount: Int
33+ var isBlocked: Bool
34+
35+ static var csvHeading: String {
36+ return "uuid, имя, телефон, админ, количество активных бронирований, в черном списке\n"
37+ }
38+
39+ var toString: String {
40+ return "\(uuid), \(name ?? "❔"), +79\(phoneNumber), \(isAdmin), \(reservationCount), \(isBlocked)"
41+ }
3342}
Hookah Tau/Supporting Files/Assets.xcassets/admin.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "admin.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/admin.imageset/admin.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/blacklist.imageset/Contents.jsonnew file+15
@@ -0,0 +1,15 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "blacklist.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ },
12+ "properties" : {
13+ "preserves-vector-representation" : true
14+ }
15+}
Hookah Tau/Supporting Files/Assets.xcassets/blacklist.imageset/blacklist.pdfnew file

Binary file not shown.