Add pricing entry flow and platform admin foundations
This commit is contained in:
@@ -40,9 +40,7 @@ class _SignInScreenState extends ConsumerState<SignInScreen> {
|
||||
|
||||
Future<void> _submit() async {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
await ref
|
||||
.read(authProvider.notifier)
|
||||
.signIn(
|
||||
await ref.read(authProvider.notifier).signIn(
|
||||
_emailCtrl.text.trim(),
|
||||
_passCtrl.text,
|
||||
rememberSession: _rememberMe,
|
||||
@@ -98,10 +96,13 @@ class _SignInScreenState extends ConsumerState<SignInScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
child:
|
||||
const Center(child: ToothLogo(size: 34, color: Colors.white)),
|
||||
child: const Center(
|
||||
child: ToothLogo(size: 34, color: Colors.white)),
|
||||
),
|
||||
).animate().fadeIn(duration: 400.ms).scale(begin: const Offset(0.8, 0.8)),
|
||||
)
|
||||
.animate()
|
||||
.fadeIn(duration: 400.ms)
|
||||
.scale(begin: const Offset(0.8, 0.8)),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
Center(
|
||||
@@ -114,7 +115,10 @@ class _SignInScreenState extends ConsumerState<SignInScreen> {
|
||||
letterSpacing: -0.5,
|
||||
),
|
||||
),
|
||||
).animate(delay: 60.ms).fadeIn(duration: 400.ms).slideY(begin: 0.1),
|
||||
)
|
||||
.animate(delay: 60.ms)
|
||||
.fadeIn(duration: 400.ms)
|
||||
.slideY(begin: 0.1),
|
||||
const SizedBox(height: 6),
|
||||
Center(
|
||||
child: Text(
|
||||
@@ -169,10 +173,18 @@ class _SignInScreenState extends ConsumerState<SignInScreen> {
|
||||
),
|
||||
),
|
||||
),
|
||||
const Positioned(top: -140, left: -140, child: _Ring(size: 520, opacity: 0.06)),
|
||||
const Positioned(bottom: -100, right: -100, child: _Ring(size: 400, opacity: 0.05)),
|
||||
const Positioned(top: 160, right: 60, child: _Ring(size: 100, opacity: 0.09)),
|
||||
const Positioned(bottom: 220, left: 60, child: _Ring(size: 70, opacity: 0.07)),
|
||||
const Positioned(
|
||||
top: -140,
|
||||
left: -140,
|
||||
child: _Ring(size: 520, opacity: 0.06)),
|
||||
const Positioned(
|
||||
bottom: -100,
|
||||
right: -100,
|
||||
child: _Ring(size: 400, opacity: 0.05)),
|
||||
const Positioned(
|
||||
top: 160, right: 60, child: _Ring(size: 100, opacity: 0.09)),
|
||||
const Positioned(
|
||||
bottom: 220, left: 60, child: _Ring(size: 70, opacity: 0.07)),
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 64, vertical: 52),
|
||||
@@ -356,7 +368,6 @@ class _SignInScreenState extends ConsumerState<SignInScreen> {
|
||||
(v == null || v.trim().isEmpty) ? s.emailRequired : null,
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
|
||||
_Field(
|
||||
controller: _passCtrl,
|
||||
label: s.password,
|
||||
@@ -377,44 +388,29 @@ class _SignInScreenState extends ConsumerState<SignInScreen> {
|
||||
validator: (v) =>
|
||||
(v == null || v.isEmpty) ? s.passwordRequired : null,
|
||||
),
|
||||
|
||||
const SizedBox(height: 12),
|
||||
|
||||
InkWell(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
onTap: auth.isLoading
|
||||
CheckboxListTile(
|
||||
value: _rememberMe,
|
||||
onChanged: auth.isLoading
|
||||
? null
|
||||
: () => setState(() => _rememberMe = !_rememberMe),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: _rememberMe,
|
||||
onChanged: auth.isLoading
|
||||
? null
|
||||
: (value) => setState(() => _rememberMe = value ?? true),
|
||||
activeColor: const Color(0xFF0D4C85),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
s.rememberMe,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppColors.textSecondary,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
: (value) => setState(() => _rememberMe = value ?? true),
|
||||
activeColor: const Color(0xFF0D4C85),
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
dense: true,
|
||||
title: Text(
|
||||
s.rememberMe,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppColors.textSecondary,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
if (auth.error != null) ...[
|
||||
const SizedBox(height: 14),
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFEF2F2),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
@@ -437,9 +433,7 @@ class _SignInScreenState extends ConsumerState<SignInScreen> {
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
@@ -488,24 +482,36 @@ class _SignInScreenState extends ConsumerState<SignInScreen> {
|
||||
// ── Sign-up link ───────────────────────────────────────────────────────────
|
||||
|
||||
Widget _buildSignUpLink(BuildContext context, AppStrings s) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
return Column(
|
||||
children: [
|
||||
Text(
|
||||
s.noAccount,
|
||||
style:
|
||||
const TextStyle(color: AppColors.textSecondary, fontSize: 14),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
s.noAccount,
|
||||
style:
|
||||
const TextStyle(color: AppColors.textSecondary, fontSize: 14),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => context.go(routeSignUp),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: const Color(0xFF0D4C85),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
),
|
||||
child: Text(
|
||||
s.signUp,
|
||||
style:
|
||||
const TextStyle(fontWeight: FontWeight.w700, fontSize: 14),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => context.go(routeSignUp),
|
||||
TextButton.icon(
|
||||
onPressed: () => context.go(routeWelcome),
|
||||
icon: const Icon(Icons.workspace_premium_outlined, size: 18),
|
||||
label: const Text('Paketleri İncele'),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: const Color(0xFF0D4C85),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
),
|
||||
child: Text(
|
||||
s.signUp,
|
||||
style:
|
||||
const TextStyle(fontWeight: FontWeight.w700, fontSize: 14),
|
||||
foregroundColor: AppColors.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -726,7 +732,8 @@ class _DashboardPreviewCard extends StatelessWidget {
|
||||
const SizedBox(height: 18),
|
||||
const Row(
|
||||
children: [
|
||||
_StatChip(value: '24', label: 'Aktif', color: Color(0xFF60A5FA)),
|
||||
_StatChip(
|
||||
value: '24', label: 'Aktif', color: Color(0xFF60A5FA)),
|
||||
SizedBox(width: 8),
|
||||
_StatChip(
|
||||
value: '8', label: 'Bekliyor', color: Color(0xFFFBBF24)),
|
||||
@@ -915,8 +922,7 @@ class _Field extends StatelessWidget {
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide:
|
||||
const BorderSide(color: AppColors.cancelled, width: 1.5),
|
||||
borderSide: const BorderSide(color: AppColors.cancelled, width: 1.5),
|
||||
),
|
||||
focusedErrorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
@@ -924,8 +930,8 @@ class _Field extends StatelessWidget {
|
||||
),
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||
labelStyle: const TextStyle(
|
||||
color: AppColors.textSecondary, fontSize: 14),
|
||||
labelStyle:
|
||||
const TextStyle(color: AppColors.textSecondary, fontSize: 14),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user